1 说明

1.1 Realm的作用

Realm和认证和授权时的数据交互有关,相当于DAO层。

1.2 AuthorizingRealm

》层次关系图

》作用
继承AuthorizingRealm类后重写doGetAuthorizationInfo和doGetAuthenticationInfo就可以实现授权和认证逻辑。

2 代码实现

2.1 创建一个maven项目并引入shiro、junit依赖

2.2 创建一个类继承AuthorizingRealm

2.3 重写doGetAuthorizationInfo和doGetAuthenticationInfo

2.4 完整代码

package com.xunyji.demo04.realm;

import com.xunyji.demo0.StringUtilsXyj;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set; /**
* @author AltEnter
* @create 2019-01-23 20:32
* @desc 自定义Realm,md
**/
public class CustomRealm extends AuthorizingRealm { private Logger log = LoggerFactory.getLogger(this.getClass()); private Map<String, String> userMap = new HashMap<String, String>(); {
getName();
// userMap.put("fury", "111111");
// userMap.put("fury", "96e79218965eb72c92a549dd5a330112");
userMap.put("fury", "66b747dd6c7c7c8ca4227a67fff8ea6e");
} /**
* 授权逻辑
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 01 获取用户名
String username = (String) principals.getPrimaryPrincipal();
// 02 获取权限集合
Set<String> permissionSet = getPermissionSetByUsername(username);
// 03 获取角色集合
Set<String> roleSet = getRoleSetByUsername(username);
// 04 封装SimpleAuthorizationInfo对象
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(roleSet);
simpleAuthorizationInfo.setStringPermissions(permissionSet);
return simpleAuthorizationInfo;
} /**
* 根据用户名获取权限集合
* @param username
* @return
*/
private Set<String> getPermissionSetByUsername(String username) {
HashSet<String> permissionSet = new HashSet<>();
permissionSet.add("user:create");
permissionSet.add("user:delete");
permissionSet.add("user:update");
return permissionSet;
} /**
* 根据用户名获取角色集合
* @param username
* @return
*/
private Set<String> getRoleSetByUsername(String username) {
HashSet<String> roleSet = new HashSet<>();
roleSet.add("admin");
roleSet.add("user");
return roleSet;
} /**
* 认证逻辑
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 01 获取前端用户名和密码
String username = (String) token.getPrincipal();
String passoword = new String((char[]) token.getCredentials());
if (StringUtilsXyj.isEmpty(passoword) || StringUtilsXyj.isEmpty(username)) {
String msg = "doGetAuthenticationInfo - 用户名和密码不能为空";
log.info(msg);
throw new RuntimeException(msg);
}
log.info(String.format("doGetAuthenticationInfo - 前端传过来的用户信息为 - 用户名为:%s ,用户密码为:%s", username, passoword));
System.out.println(String.format("doGetAuthenticationInfo - 前端传过来的用户信息为 - 用户名为:%s ,用户密码为:%s", username, passoword)); // 02 根据用户名获取用户密码
String pwd = getPasswordByUsername(username);
// 03 前端密码加密加盐处理
passoword = string2Md5Hash(passoword, "AltEnter");
System.out.println("加盐加密后的密码为:" + pwd); // 04 密码比对
if (passoword.equals(pwd)) {
// 封装SimpleAuthenticationInfo对象
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, passoword, getName());
// 加盐处理
simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("AltEnter"));
return simpleAuthenticationInfo;
} else {
String msg = "doGetAuthenticationInfo - 用户名或者密码错误";
log.info(msg);
System.out.println(msg);
throw new RuntimeException(msg);
}
} /**
* 密码加密加盐处理
* @param password 待加密密码
* @param salt 盐
* @return 经过加密和加盐处理后的密码
*/
private String string2Md5Hash(String password, String salt) {
return new Md5Hash(password, salt).toString();
} /**
* 根据用户名获取密码
* @param username
* @return
*/
private String getPasswordByUsername(String username) {
String pwd = userMap.get(username);
return pwd;
} public static void main(String[] args) {
// Md5Hash md5Hash = new Md5Hash("111111");
// System.out.println("111111加密后的结果为:" + md5Hash.toString());
// 96e79218965eb72c92a549dd5a330112 Md5Hash md5Hash = new Md5Hash("111111", "AltEnter");
System.out.println("111111经过MD5加密和AltEnter加盐后的结果为:" + md5Hash.toString());
// 66b747dd6c7c7c8ca4227a67fff8ea6e
}
}

3 测试类

package com.xunyji.demo04.realm;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test; import static org.junit.Assert.*; public class CustomRealmTest {
@Test
public void test01() {
CustomRealm customRealm = new CustomRealm();
// shiro加密 start
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//选择加密方式
matcher.setHashAlgorithmName("md5");
//加密次数
matcher.setHashIterations(1);
// 给自定义Realm设置加密规则
customRealm.setCredentialsMatcher(matcher);
// shiro加密 end // 更改认证策略 start
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
FirstSuccessfulStrategy firstSuccessfulStrategy = new FirstSuccessfulStrategy();
ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
modularRealmAuthenticator.setAuthenticationStrategy(firstSuccessfulStrategy);
defaultSecurityManager.setAuthenticator(modularRealmAuthenticator);
// 更改认证策略 end defaultSecurityManager.setRealm(customRealm); SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("fury", "111111"); subject.login(token);
System.out.println(String.format("认证信息为:%s", subject.isAuthenticated())); System.out.println(String.format("拥有admin角色吗? - %s", subject.hasRole("admin")));
System.out.println(String.format("拥有user:create权限吗? - %s", subject.isPermitted("user:create"))); subject.logout();
System.out.println(String.format("认证信息为:%s", subject.isAuthenticated())); }
}

4 注意

4.1 可以给SecurityManager设置认证策略

4.2 可以给Realm设置MD5加密

4.3 SecurityManager必须先设置认证策略再设置Realm

Shrio04 自定义Realm的更多相关文章

  1. 权限框架 - shiro 自定义realm

    上篇文章中是使用的默认realm来实现的简单登录,这仅仅只是个demo,真正项目中使用肯定是需要连接数据库的 首先创建自定义realm文件,如下: 在shiro中注入自定义realm的完全限定类名: ...

  2. Shrio认证详解+自定义Realm

    Authentication(身份认证)是Shiro权限控制的第一步,用来告诉系统你就是你. 在提交认证的时候,我们需要给系统提交两个信息: Principals:是一个表示用户的唯一属性,可以是用户 ...

  3. Shiro第二篇【介绍Shiro、认证流程、自定义realm、自定义realm支持md5】

    什么是Shiro shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证.用户授权. spring中有spring security (原名Acegi),是一个权限框架,它和sp ...

  4. shiro(二)自定义realm,模拟数据库查询验证

    自定义一个realm类,实现realm接口 package com; import org.apache.shiro.authc.*; import org.apache.shiro.realm.Re ...

  5. shiro自定义Realm

    1.1 自定义Realm 上边的程序使用的是shiro自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm. ...

  6. Shiro入门 - 通过自定义Realm连数数据库进行授权

    shiro-realm.ini [main] #自定义Realm myRealm=test.shiro.MyRealm #将myRealm设置到securityManager,相当于Spring中的注 ...

  7. Shiro入门 - 通过自定义Realm连数数据库进行认证(md5+salt形式)

    shiro-realm-md5.ini [main] #定义凭证匹配器 credentialsMatcher=org.apache.shiro.authc.credential.HashedCrede ...

  8. Shiro入门 - 通过自定义Realm连数数据库进行认证

    添加shiro-realm.ini文件 [main] #自定义Realm myRealm=test.shiro.MyRealm #将myRealm设置到securityManager,相当于Sprin ...

  9. shiro教程2(自定义Realm)

    通过shiro教程1我们发现仅仅将数据源信息定义在ini文件中与我们实际开发环境有很大不兼容,所以我们希望能够自定义Realm. 自定义Realm的实现 创建自定义Realmjava类 创建一个jav ...

随机推荐

  1. pandas 之 concat

    本文摘自:http://pandas.pydata.org/pandas-docs/stable/merging.html 前提: ide: liuqian@ubuntu:~$ ipython 准备: ...

  2. Windows环境下 PyQt5 如何安装MySql驱动 (PyQt5连接MYSQL时显示Driver not loaded解决方案)

    参考文章: https://blog.csdn.net/qq_38198744/article/details/80261695 前文说过如何在Ubuntu环境下 为PyQt5  安装MySql驱动, ...

  3. 从U-Boot显示Logo到Android

    /******************************************************************************* * 从U-Boot显示Logo到And ...

  4. appium使用

    学过selenium的朋友再来看appium,基本上就是一个环境折腾问题,还有一个就是初始化Driver的问题,以下代码是初始化Driver WebDriver driver = null; // 驱 ...

  5. 使用nomad && consul && fabio 创建简单的微服务系统

    具体每个组件的功能就不详细说明了 nomad 一个调度工具,consul 一个服务发现,健康检查多数据中心支持的工具 fabio 一个基于consul的负载均衡&&动态路由工具,对于集 ...

  6. TimescaleDB 简单试用

    TimescaleDB 是一个对于pg进行了改造的时序数据库 安装测试使用docker 安装&&运行 docker run -d --name timescaledb -p 5432: ...

  7. RabbitMQ消息队列安装

    [root@VM_119_179_centos ~]# rpm -ivh erlang-19.0.4-1.el6.x86_64.rpm [root@VM_119_179_centos ~]# rpm ...

  8. Linux进程间通信——使用共享内存(转)

    一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存. ...

  9. pfsense openvpn上网终于通了

    先看配置,等会在说过程中遇到的问题: 1.openvpn配置: /var/etc/openvpn/server2.conf下: port 1195 proto tcp dev tap writepid ...

  10. Android 查看Android版本的方法

    1.通过源码查看 Android 版本 路径:build/core/version_defaults.mk PLATFORM_VERSION := 2.通过编译时终端输出查看 ============ ...