Shiro---授权源码分析

一.步骤总结

1.首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager,而SecurityManage接着委托给Authorizer

2.Authorizer是真正的授权者,如果我们调用如.isPermitted(“user:view”),其首先会通过PermissionResolver把字符串换成相应的permission实例

3.在进行授权之前,其会调用相应的realm获取Subject相应的角色/权限用于匹配传入的角色/权限

4.Authorizer会判断realm的角色/权限是否传入的匹配 ,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted/hasRole会返回true,否则返回false表示授权失败

二.源码解析

1.调用Subject.isPermitted/hasRole接口

boolean[] booleans = subject.isPermitted("user:insert", "user:select");

2.进入到isPermitted()中,如果有Principals就开始调用SecurityManager的isPermitted方法,即subject委托给SecurityManager

  public boolean[] isPermitted(String... permissions) {
       //如果有Principals就开始
        if (hasPrincipals()) {
            return securityManager.isPermitted(getPrincipals(), permissions);
        } else {
            return new boolean[permissions.length];
        }
    }

3.进入到isPermitted中,会看到委托给了授权器Authorizer的isPermitted方法

 public boolean[] isPermitted(PrincipalCollection principals, String... permissions) {
        return this.authorizer.isPermitted(principals, permissions);
    }

4.进入到授权器的isPermitted方法中,在这里,我们可以看到底层是用for循环来对我们传进来的权限进行逐一比对
1)当i0时.,在isPermitted(principals, permissions[i])中,把用户信息和传进来的第一个权限传给了isPermitted方法,然后把结果赋值给了new 出来的boolean类型的数组isPermitted[ 0],
2)当i
1时.,在isPermitted(principals, permissions[i])中,把用户信息和传进来的第一个权限传给了isPermitted方法,然后把结果赋值给了new 出来的boolean类型的数组isPermitted[1]

    public boolean[] isPermitted(PrincipalCollection principals, String... permissions) {
        assertRealmsConfigured();
        if (permissions != null && permissions.length > 0) {
        //先new了一个boolean的数组,数组的长度由传进来的权限个数决定,数组的默认值都是false,并开始做for循环,对每个权限进行判断是否拥有
            boolean[] isPermitted = new boolean[permissions.length];
            for (int i = 0; i < permissions.length; i++) {
                isPermitted[i] = isPermitted(principals, permissions[i]);
            }
            return isPermitted;
        }
        return new boolean[0];
    }

5.点进去isPermitted(principals, permissions[i]);在这个方法中,会先获取到所有的Realm,在这边我们自定义了一个realm.所以获取到的是我们自己定义的realm,接着(Authorizer) realm).isPermitted(principals, permission)这个的方法内部其实就是把传进来的字符串权限转成了 Permission对象
在这里插入图片描述

  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;
    }

把字符串转成了 Permission对象

 public boolean isPermitted(PrincipalCollection principals, String permission) {
        Permission p = getPermissionResolver().resolvePermission(permission);
        return isPermitted(principals, p);
    }

6.在转成了字符串后,我们进入到 return isPermitted(principals, p)中

   public boolean isPermitted(PrincipalCollection principals, Permission permission) {
        AuthorizationInfo info = getAuthorizationInfo(principals);
        return isPermitted(permission, info);
    }

7.再进入到 getAuthorizationInfo(principals)中,这一步的逻辑是
1)如果principals为空,则返回null
2)如果principals不为空,则先从缓存中获取info信息,如果info不为空,则通过principals获取key,再通过key获取info信息,info包含了该用户授权过的角色和权限
3)如果缓存中没有info,则调用 doGetAuthorizationInfo(principals);方法去获取info,这个方法就是我们自定义的myRealm中的方法,获取到info后判断是否开启了缓存,即cache是否为null,如果不为空,则把principals作为key,info作为值存到缓存中
4)最终返回info

 protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {

        if (principals == null) {
            return null;
        }

        AuthorizationInfo info = null;

        if (log.isTraceEnabled()) {
            log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");
        }

        Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
        if (cache != null) {
            if (log.isTraceEnabled()) {
                log.trace("Attempting to retrieve the AuthorizationInfo from cache.");
            }
            Object key = getAuthorizationCacheKey(principals);
            info = cache.get(key);
            if (log.isTraceEnabled()) {
                if (info == null) {
                    log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");
                } else {
                    log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");
                }
            }
        }


        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);
            }
        }

        return info;
    }
  1. 此时第6步中的
  2. AuthorizationInfo info = getAuthorizationInfo(principals)就会得到info信息,并返回
 return isPermitted(permission, info)
 

10.再进到return isPermitted(permission, info)中,看看得到是怎么进行权限认证的,这个认证的思路就是
1)先将info中包含的权限集合获取出来,并遍历这个集合,逐一和传进来的第一个权限对象permission进行比对,如果相等,就返回true,如果都不相等,就返回false
2)最后将这个结果逐一返回给最前面,就得到了boolean数组中的第一个值
3)再返回来进行第二个权限判断

    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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值