一、自定义Realm授权
前提:认证通过,查看Realm接口的继承关系结构图如下,要想通过自定义的Realm实现授权,只需继承AuthorizingRealm并重写方法即可
二、实现过程
1、新建module,添加如下pom依赖
<properties> <shiro.version>1.4.1</shiro.version> <loggingg.version>1.2</loggingg.version> </properties> <dependencies> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>${loggingg.version}</version> </dependency> </dependencies>
2、新建UserRealm类继承AuthorizingRealm,重写方法
public class UserRealm extends AuthorizingRealm { private UserService userService = new UserServiceImpl(); private RoleService roleService = new RoleServiceImpl(); private PermissionService permissionService = new PermissionServiceImpl(); /** * 做认证 * * @param token * @return * @throws AuthenticationException */ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = token.getPrincipal().toString(); System.out.println("自定义Realm:" + username); User user = userService.queryUserByUserName(username); if (user != null) { List<String> roles = roleService.queryRoleByUserName(username); List<String> permissions = permissionService.queryPermissionByUserName(username); ActivityUser activityUser = new ActivityUser(user, roles, permissions); //参数1:可以传任意对象|参数2:数据库中的用户密码|参数3:当前类名 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(activityUser, user.getPwd(), this.getName()); return info; } else { return null; } } //授权方法 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); System.out.println("doGetAuthorizationInfo被回调了"); // Object primaryPrincipal = principal.getPrimaryPrincipal(); System.out.println(primaryPrincipal); ActivityUser activityUser = (ActivityUser) principal.getPrimaryPrincipal(); List<String> roles = activityUser.getRoles(); if (roles != null && roles.size() > 0) { info.addRoles(roles); } List<String> permissins = activityUser.getPermissins(); if (permissins!=null&&permissins.size()>0) { info.addStringPermissions(permissins); } //判断如果是超级管理员 //info.addStringPermission("*:*"); return info; }
3、test类测试方法
public class TestAuthorizationRealm { public static void main(String[] args) { //1.模拟前台传递的用户名和密码 String username = "zhangsan"; String password = "123456"; //2.创建安全管理器的工厂 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //3.通过安全管理器工厂获取安全管理器 DefaultSecurityManager securityManager = (DefaultSecurityManager)factory.getInstance(); //4.创建自定义的Realm UserRealm userRealm = new UserRealm(); //5.设置自定义的Realm securityManager.setRealm(userRealm); //6.将安全管理器绑定到当前运行环境 SecurityUtils.setSecurityManager(securityManager); //7.从当前环境中获取Subject主体 Subject subject1 = SecurityUtils.getSubject(); //8.调用主体的登录方法 try { subject1.login(new UsernamePasswordToken(username,password)); System.out.println("登录成功~"); // Object principal = subject1.getPrincipal(); // System.out.println(principal); } catch (IncorrectCredentialsException e) { System.out.println("密码不正确"); }catch (UnknownAccountException e) { System.out.println("用户名不存在"); } boolean role1 = subject1.hasRole("role1"); boolean role2 = subject1.hasRole("role1"); System.out.println(role1); boolean permitted = subject1.isPermitted("user:add"); System.out.println(permitted); } }
三、分析
1、在进行授权的时候,每进行一次授权都会进行一次回调自定义Realm的doGetAuthorizationInfo方法,验证如下:
①在授权方法内部打印日志
②test类做3次授权,查看控制台如下:
2、认证时候进行查库,查角色、权限,并封装对象,避免多次调用授权方法导致频繁查库导致性能下降
四、总结
1、每次进行授权时,就会调用授权方法(通过打印日志可以验证)
2、避免在授权回调方法中查库而导致性能下降
3、授权方法参数可以获取到认证方法中放入的第一个任意参数(图中有说明,当然也可以通过subject.getPrincipal()方法获取该参数),所以我采用封装的方式,实现多次调用授权方法时也是同一个对象,避免频繁查库