一、自定義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()方法獲取該參數),所以我采用封裝的方式,實現多次調用授權方法時也是同一個對象,避免頻繁查庫