Shiro权限验证最详细的代码流转分析

来源:互联网 发布:如何注册网络作家 编辑:程序博客网 时间:2024/06/04 19:45

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