魯春利的工做筆記,好記性不如爛筆頭java
Shiro配置文件(shiro-authorize-permission.ini)數據庫
[main] # 定義變量 # 變量名=全類名 [users] # 用戶名=密碼,角色1,角色2,...,角色N lucl=123,role1,role2 zs=123,role1 [roles] # 角色=權限1,權限2,...,權限N role1=user:create,user:update role2=user:create,user:delete
單元測試apache
/** * 基於資源的訪問控制 */ @Test public void testWhetherHasPermission () { // 一、獲取SecurityManager工廠,此處使用Ini配置文件初始化SecurityManager Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro/authorize/shiro-authorize-permission.ini"); // 二、獲得SecurityManager實例並綁定給SecurityUtils org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); // 三、獲得Subject及建立用戶名/密碼身份驗證Token(即用戶身份/憑證) Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("lucl", "123"); try{ // 四、登陸,即身份驗證 subject.login(token); } catch (AuthenticationException e) { // 五、身份驗證失敗 logger.info("用戶身份驗證失敗"); e.printStackTrace(); } // 用戶身份獲得確認 if (subject.isAuthenticated()) { logger.info("用戶登陸成功。"); /** * 進行權限判斷 */ // 判斷擁有權限:user:create Assert.assertTrue(subject.isPermitted("user:create")); // 判斷擁有權限:user:update and user:delete Assert.assertTrue(subject.isPermittedAll("user:update", "user:delete")); // 判斷沒有權限:user:view Assert.assertFalse(subject.isPermitted("user:view")); // 斷言擁有權限:user:create subject.checkPermission("user:create"); // 斷言擁有權限:user:delete and user:update subject.checkPermissions("user:delete", "user:update"); // 斷言擁有權限:user:view 失敗拋出異常 subject.checkPermissions("user:view"); } else { logger.info("用戶登陸失敗。"); } // 六、退出 subject.logout(); }
isPermitted過程緩存
subject.isPermittedapp
package org.apache.shiro.subject.support; public class DelegatingSubject implements Subject { /** hasPrincipals()判斷身份信息,身份信息是在login方法登陸後賦值的 */ public boolean isPermitted(String permission) { return hasPrincipals() && securityManager.isPermitted(getPrincipals(), permission); } public void login(AuthenticationToken token) throws AuthenticationException { clearRunAsIdentitiesInternal(); /** 身份認證 */ Subject subject = securityManager.login(this, token); PrincipalCollection principals; String host = null; if (subject instanceof DelegatingSubject) { DelegatingSubject delegating = (DelegatingSubject) subject; //we have to do this in case there are assumed identities - we don't want to lose the 'real' principals: principals = delegating.principals; host = delegating.host; } else { principals = subject.getPrincipals(); } if (principals == null || principals.isEmpty()) { // 異常信息 throw new IllegalStateException(msg); } this.principals = principals; this.authenticated = true; // 代碼略 } }
securityManager.isPermittedide
securityManager的實現爲DefaultSecurityManager,但DefaultSecurityManager無isPermitted方法。
單元測試
org.apache.shiro.mgt.DefaultSecurityManager extends org.apache.shiro.mgt.SessionsSecurityManager extends org.apache.shiro.mgt.AuthorizingSecurityManager extends org.apache.shiro.mgt.AuthenticatingSecurityManager
調用AuthorizingSecurityManager的isPermitted方法
測試
package org.apache.shiro.mgt; public abstract class AuthorizingSecurityManager extends AuthenticatingSecurityManager { /** * The wrapped instance to which all of this SecurityManager authorization calls are delegated. * 受權的核心接口 */ private Authorizer authorizer; public AuthorizingSecurityManager() { super(); this.authorizer = new ModularRealmAuthorizer(); } public boolean isPermitted(PrincipalCollection principals, Permission permission) { return this.authorizer.isPermitted(principals, permission); } // 其餘代碼略 }
ModularRealmAuthorizer.isPermitted方法
this
package org.apache.shiro.authz; public class ModularRealmAuthorizer implements Authorizer, PermissionResolverAware, RolePermissionResolverAware { /** * The realms to consult during any authorization check. */ protected Collection<Realm> realms; protected PermissionResolver permissionResolver; protected RolePermissionResolver rolePermissionResolver; public ModularRealmAuthorizer() { // 無參構造方法 } public ModularRealmAuthorizer(Collection<Realm> realms) { setRealms(realms); } /* 權限判斷 */ public boolean isPermitted(PrincipalCollection principals, Permission permission) { assertRealmsConfigured(); for (Realm realm : getRealms()) { if (!(realm instanceof Authorizer)) continue; if (((Authorizer) realm).isPermitted(principals, permission)) { return true; } } return false; } }
轉了一圈,具體的isPermitted仍是經過最終的realm來完成(IniRealm)
spa
org.apache.shiro.realm.text.IniRealm extends org.apache.shiro.realm.text.TextConfigurationRealm extends org.apache.shiro.realm.SimpleAccountRealm extends org.apache.shiro.realm.AuthorizingRealm
AuthorizingRealm.isPermitted被調用
package org.apache.shiro.realm; /** * An AuthorizingRealm extends the AuthenticatingRealm's capabilities by adding Authorization (access control) support. * @see org.apache.shiro.authz.SimpleAuthorizationInfo * @since 0.2 */ public abstract class AuthorizingRealm extends AuthenticatingRealm implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware { private PermissionResolver permissionResolver; private RolePermissionResolver permissionRoleResolver; public AuthorizingRealm() { this(null, null); } public AuthorizingRealm(CacheManager cacheManager) { this(cacheManager, null); } public AuthorizingRealm(CredentialsMatcher matcher) { this(null, matcher); } public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) { /** super()會調用父類的無參構造方法,也就是new AuthenticatingRealm() {this(null, new SimpleCredentialsMatcher());} */ super(); if (cacheManager != null) setCacheManager(cacheManager); if (matcher != null) setCredentialsMatcher(matcher); this.authorizationCachingEnabled = true; // permissionResolver的實現類,自定義Permission時自定了也自定義了這個東西 this.permissionResolver = new WildcardPermissionResolver(); // 代碼略 } public boolean isPermitted(PrincipalCollection principals, String permission) { // WildcardPermissionResolver.resolvePermission {return new WildcardPermission(permissionString);} Permission p = getPermissionResolver().resolvePermission(permission); return isPermitted(principals, p); } public boolean isPermitted(PrincipalCollection principals, Permission permission) { /** * getAuthorizationInfo(principals)實際返回的是SimpleAccount; * 若是咱們在自定義的Realm中實現了info.add("system:edit:1"),那麼SimpleAccount就獲取到了其擁有的權限列表: * 說明:也就是shiro不維護權限信息,其應該具備的權限信息是由業務系統根據實際狀況來設定的 * isPermitted會比較傳入的權限字符串,是否在實際設定的權限列表中(權限列表通常根據登陸用戶權限從數據庫中讀取並加載) */ AuthorizationInfo info = getAuthorizationInfo(principals); return isPermitted(permission, info); } /** 最終的判斷方法(權限集合是在Realm實現時添加的權限列表,如info.add("system:edit:1")) */ protected boolean isPermitted(Permission permission, AuthorizationInfo info) { Collection<Permission> perms = getPermissions(info); if (perms != null && !perms.isEmpty()) { for (Permission perm : perms) { /** Permission的implies方法總算是被調用到了 */ if (perm.implies(permission)) { return true; } } } return false; } protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) { if (principals == null) { return null; } AuthorizationInfo info = null; // 代碼略,主要實現從緩存中獲取受權數據 if (info == null) { // Call template method if the info was not found in a cache /** 這是最核心的受權實現方法,用戶自定義方法通常重寫該方法,實現本身的受權過程 */ info = doGetAuthorizationInfo(principals); // If the info is not null and the cache has been created, then cache the authorization info. // 代碼略,獲取後從新加入緩存中 } return info; } // 該類的doGetAuthorizationInfo方法爲抽象方法,須要子類根據身份信息實現本身的受權 protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals); }
SimpleAccountRealm.doGetAuthorizationInfo方法
package org.apache.shiro.realm; public class SimpleAccountRealm extends AuthorizingRealm { // 部分代碼略 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = getUsername(principals); USERS_LOCK.readLock().lock(); try { return this.users.get(username); // 返回SimpleAccount } finally { USERS_LOCK.readLock().unlock(); } } }