Shiro权限验证
1.测试类
首先调用
subject().isPermitted("user1:update");
subject会委托给SecurityManager
而SecurityManager接着会委托给Authorizer;
Authorizer是真正的授权者
Authorizer是个接口,会接着调用它实现类(ModularRealmAuthorizer)的isPermitted方法去做认证
循环验证是否权限匹配可以看出只要有一个权限验证通过即返回为true
public boolean isPermitted(PrincipalCollection principals, String permission) { assertRealmsConfigured(); for (Realm realm : getRealms()) { if (!(realm instanceof Authorizer)) continue; if (((Authorizer) realm).isPermitted(principals, permission)) { return true; } } return false; }其中
assertRealmsConfigured方法源码为:其作用主要判断realm是否为空(这个方法蛮好的,学学)
protected void assertRealmsConfigured() throws IllegalStateException { Collection<Realm> realms = getRealms(); if (realms == null || realms.isEmpty()) { String msg = "Configuration error: No realms have been configured! One or more realms must be " + "present to execute an authorization operation."; throw new IllegalStateException(msg); } }
此时上面哪个isPermitted(principals, permission)方法调用其实现接口(Authorizer)的方法isPermitted(principals, permission)
进而调用其实现类(AuthorizingRealm)的方法
首先对传进来的要验证的权限进行解析
用开发人员指定的解析器BitAndWildPermissionResolver
public boolean isPermitted(PrincipalCollection principals, String permission) { Permission p = getPermissionResolver().resolvePermission(permission); return isPermitted(principals, p); }
用自定义的权限解析器去把字符串的权限转换成Permission类型的权限
public class BitAndWildPermissionResolver implements PermissionResolver { public Permission resolvePermission(String permissionString) { //以+号开始的都走自定义的权限解析器 if(permissionString.startsWith("+")){ return new BitPermission(permissionString); } //其余的走shiro,默认的通配符权限解析器 return new WildcardPermission(permissionString); } }
然后对传入的权限进行比较 :
public boolean isPermitted(PrincipalCollection principals, Permission permission) { AuthorizationInfo info = getAuthorizationInfo(principals); return isPermitted(permission, info); }次方法作用:
(0)首先从缓存中取权限信息,如果没有才去realm里面取
Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
(1)首先从自定义的MyRealm的类中获取权限集合(原始的,未解析的,包括字符串,wild,bit各种类型的初始权限参数)
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.addRole("role1"); authorizationInfo.addRole("role2"); authorizationInfo.addObjectPermission(new BitPermission("+user1+10")); authorizationInfo.addObjectPermission(new WildcardPermission("user1:*")); authorizationInfo.addStringPermission("+user2+10"); authorizationInfo.addStringPermission("user2:*"); return authorizationInfo; }
注意:关于缓存的问题
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.
if (info != null && cache != null) {
if (log.isTraceEnabled()) {
log.trace("Caching authorization info for principals: [" + principals + "].");
}
Object key = getAuthorizationCacheKey(principals);
cache.put(key, info);
}
}
这里有判断默认的cache实现,如果你shiro中配置了缓存就会把当前权限信息缓存在缓存其中
(2)进行权限的实际比较(解析权限字符串)
return isPermitted(permission, info);关键时刻到了:
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; }
其中黄底蓝字的地方会把刚刚从自定义realm里面取得的权限信息(良莠不齐)转化成统一的Permission对象来比较
最终解析出来的权限如下(包括直接赋予的权限,以及拥有角色的所拥有的权限)
准备工作完成(要验证的权限,用户实际拥有的权限)
可以开始比较了possessPermissions
Collection<Permission> possessPermissions= getPermissions(info);
if (possessPermissions!= null && !possessPermissions.isEmpty()) {
for (Permission perm : possessPermissions) {
if (perm.implies(wantTocheckPermissions)) {
return true;
}
}
}
return false;
有一个返回true则为true