Spring Boot 使用自定义 Realm 进行认证授权
概述
虽然 jdbcRealm 已经实现了从数据库中获取用户的验证信息,但是jdbcRealm灵活性也是稍差一些的,如果要实现自己的一些特殊应用时将不能支持,这个时候可以通过自定义realm来实现身份的认证功能。
通常自定义Realm只需要继承:AuthorizingRealm
重写doGetAuthenticationInfo
(用户认证)、doGetAuthorizationInfo
(用户授权) 这两个方法即可。
自定义 Realm
创建 CustomRealm
public class CustomRealm extends AuthorizingRealm {
/**
* 模拟数据库中的用户名和密码
*/
private Map<String, String> userMap = new HashMap<>();
/**
* 使用代码块初始化数据
*/ {
userMap.put("admin", "123456");
userMap.put("test", "123456");
}
/**
* 用户授权
*
* @param principalCollection
* @return org.apache.shiro.authz.AuthorizationInfo
* @throws
* @Author: djy
* @UpdateUser:
* @Version: 0.0.1
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//这个就是SimpleAuthenticationInfo(username,password,getName()); 第一个参数
// String username= (String) SecurityUtils.getSubject().getPrincipal();
System.out.println("开始执行*******doGetAuthorizationInfo方法啦****");
System.out.println(SecurityUtils.getSubject().getPrincipal());
String username = (String) principalCollection.getPrimaryPrincipal();
//从数据库或者缓存中获取角色数据
List<String> roles = getRolesByUsername(username);
//从数据库或者缓存中获取权限数据
List<String> permissions = getPerminssionsByUsername(username);
//创建AuthorizationInfo,并设置角色和权限信息
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addStringPermissions(permissions);
authorizationInfo.addRoles(roles);
return authorizationInfo;
}
/**
* 用户认证
*
* @param authenticationToken
* @return org.apache.shiro.authc.AuthenticationInfo
* @throws
* @Author: djy
* @UpdateUser:
* @Version: 0.0.1
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("开始执行*******doGetAuthenticationInfo方法啦****");
//获取登录用户名
String userName = (String) authenticationToken.getPrincipal();
//通过用户名到数据库获取用户信息
String password = getPasswordByUsername(userName);
if (null == password) {
return null;
}
System.out.println("密码为:" + password);
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, password, getName());
return authenticationInfo;
}
/**
* 模拟通过数据库获取权限数据
*
* @param username
* @return java.util.List<java.lang.String>
* @throws
* @Author: djy
* @UpdateUser:
* @Version: 0.0.1
*/
private List<String> getPerminssionsByUsername(String username) {
List<String> permissions = new ArrayList<>();
/**
* 只有是 admin 用户才有 新增、删除权限
*/
if (username.equals("admin")) {
permissions.add("user:delete");
permissions.add("user:add");
}
permissions.add("user:edit");
permissions.add("user:list");
return permissions;
}
/**
* 模拟通过数据库获取用户角色信息
*
* @param username
* @return java.util.List<java.lang.String>
* @throws
* @Author: djy
* @UpdateUser:
* @Version: 0.0.1
*/
private List<String> getRolesByUsername(String username) {
List<String> roles = new ArrayList<>();
if (username.equals("admin")) {
roles.add("admin");
}
roles.add("test");
return roles;
}
/**
* 通过用户名查询密码,模拟数据库查询
*
* @param userName
* @return java.lang.String
* @throws
* @Author: djy
* @UpdateUser:
* @Version: 0.0.1
*/
private String getPasswordByUsername(String userName) {
return userMap.get(userName);
}
创建 testCustomRealm 方法
@Test
public void testCustomRealm() {
CustomRealm customRealm = new CustomRealm();
//1,构建SecurityManager环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置Realm
defaultSecurityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取主体
Subject subject = SecurityUtils.getSubject();
//用户名和密码的token
UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
try {
//2,主体提交认证请求
subject.login(token);
System.out.println("认证状态:isAuthenticated=" + subject.isAuthenticated());
//检查是否有角色
subject.checkRoles("admin");
System.out.println("有admin角色");
//检查是否有权限
subject.checkPermissions("user:delete", "user:edit", "user:list", "user:add");
System.out.println("有 user:add、user:list、user:edit、user:delete权限");
} catch (IncorrectCredentialsException exception) {
System.out.println("用户名或密码错误");
} catch (LockedAccountException exception) {
System.out.println("账号已被锁定");
} catch (DisabledAccountException exception) {
System.out.println("账号已被禁用");
} catch (UnknownAccountException exception) {
System.out.println("用户不存在");
} catch (UnauthorizedException ae) {
System.out.println("用户没有权限");
}
}
测试
- 当用户 admin 登录进来的时候 程序输出
UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
- 当用户 test 登录进来的时候 程序输出
UsernamePasswordToken token = new UsernamePasswordToken("test", "123456");
- 当用户 dev 登陆进来的时候 程序输出
UsernamePasswordToken token = new UsernamePasswordToken("dev", "123456");
通过上述验证过程我们可以发现,shiro
更多的是帮助我们完成验证过程。我们需要从数据库查询当前用户的角色、权限
,把这些信息告诉shiro
框架。当我们执行用户认证的时候首先调用 doGetAuthenticationInfo
进行用户认证,当我们要校验权限的时候 就会执行
doGetAuthorizationInfo
进行授权操作。