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