上一節咱們講了自定義Realm中的認證(doGetAuthenticationInfo),這節咱們繼續講另外一個方法doGetAuthorizationInfo受權數據庫
流程以下:bash
ModularRealmAuthorizer進行多Realm匹配流程:ide
若是Realm進行受權的話,應該繼承AuthorizingRealm,其流程是:
1.一、若是調用hasRole,則直接獲取AuthorizationInfo.getRoles()與傳入的角色比較便可;
1.二、首先若是調用如isPermitted(「user:view」),首先經過PermissionResolver將權限字符串轉換成相應的Permission實例,默認使用WildcardPermissionResolver,即轉換爲通配符的WildcardPermission;
二、經過AuthorizationInfo.getObjectPermissions()獲得Permission實例集合;經過AuthorizationInfo. getStringPermissions()獲得字符串集合並經過PermissionResolver解析爲Permission實例;而後獲取用戶的角色,並經過RolePermissionResolver解析角色對應的權限集合(默認沒有實現,能夠本身提供);
三、接着調用Permission. implies(Permission p)逐個與傳入的權限比較,若是有匹配的則返回true,不然false。ui
先看一段簡單的受權方法重寫this
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//獲取用戶名
String username = (String) principals.getPrimaryPrincipal();
//此處從數據庫獲取該用戶的角色
Set<String> roles = getRolesByUserName(username);
//此處從數據庫獲取該角色的權限
Set<String> permissions = getPermissionsByUserName(username);
//放到info裏返回
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(permissions);
info.setRoles(roles);
return info;
}
複製代碼
由於咱們能夠在Shiro中同時配置多個Realm,因此呢身份信息可能就有多個;所以其提供了PrincipalCollection用於聚合這些身份信息:spa
public interface PrincipalCollection extends Iterable, Serializable {
Object getPrimaryPrincipal(); //獲得主要的身份
<T> T oneByType(Class<T> type); //根據身份類型獲取第一個
<T> Collection<T> byType(Class<T> type); //根據身份類型獲取一組
List asList(); //轉換爲List
Set asSet(); //轉換爲Set
Collection fromRealm(String realmName); //根據Realm名字獲取
Set<String> getRealmNames(); //獲取全部身份驗證經過的Realm名字
boolean isEmpty(); //判斷是否爲空
}
複製代碼
由於PrincipalCollection聚合了多個,此處最須要注意的是getPrimaryPrincipal,若是隻有一個Principal那麼直接返回便可,若是有多個Principal,則返回第一個(由於內部使用Map存儲,因此能夠認爲是返回任意一個);oneByType / byType根據憑據的類型返回相應的Principal;fromRealm根據Realm名字(每一個Principal都與一個Realm關聯)獲取相應的Principal。code
AuthorizationInfo用於聚合受權信息的:cdn
public interface AuthorizationInfo extends Serializable {
Collection<String> getRoles(); //獲取角色字符串信息
Collection<String> getStringPermissions(); //獲取權限字符串信息
Collection<Permission> getObjectPermissions(); //獲取Permission對象信息
}
複製代碼
當咱們使用AuthorizingRealm時,若是身份驗證成功,在進行受權時就經過doGetAuthorizationInfo方法獲取角色/權限信息用於受權驗證。 Shiro提供了一個實現SimpleAuthorizationInfo,大多數時候使用這個便可。對象
咱們再跟蹤一下代碼,看看是如何調用Authorizer的blog
subject.hasRole("admin")
複製代碼
public boolean hasRole(String roleIdentifier) {
return hasPrincipals() && securityManager.hasRole(getPrincipals(), roleIdentifier);
}
複製代碼
public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
return this.authorizer.hasRole(principals, roleIdentifier);
}
複製代碼
public AuthorizingSecurityManager() {
super();
this.authorizer = new ModularRealmAuthorizer();
}
複製代碼
public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
assertRealmsConfigured();
for (Realm realm : getRealms()) {
if (!(realm instanceof Authorizer)) continue;
if (((Authorizer) realm).hasRole(principals, roleIdentifier)) {
return true;
}
}
return false;
}
複製代碼
public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {
AuthorizationInfo info = getAuthorizationInfo(principal);
return hasRole(roleIdentifier, info);
}
protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
}
public boolean isPermitted(PrincipalCollection principals, String permission) {
Permission p = getPermissionResolver().resolvePermission(permission);
return isPermitted(principals, p);
}
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
AuthorizationInfo info = getAuthorizationInfo(principals);
return isPermitted(permission, info);
}
//changed visibility from private to protected for SHIRO-332
protected boolean isPermitted(Permission permission, AuthorizationInfo info) {
Collection<Permission> perms = getPermissions(info);
if (perms != null && !perms.isEmpty()) {
for (Permission perm : perms) {
if (perm.implies(permission)) {
return true;
}
}
}
return false;
}
複製代碼