shiro授权流程分析

0前言

前面认证过程的入口是subject接口的login方法,本节授权也从subject入口开始,授权包含验证角色和权限两部分。

验证角色

subject.hasRole(String)     返回true或者false,不会抛异常

subject.checkRole(String)  失败抛异常

验证权限

subject.isPermitted(String) 返回true或者false,不会抛异常

subject.checkPermission(String)  失败抛异常

 

下面是测试的demo

    @Test
    public void testRole() {

        Subject subject = login("test", "123");

        Assert.assertTrue(subject().hasRole("custom"));

        //验证失败会抛异常
        //subject().checkRole("role1");

        //退出
        subject.logout();
    }

    @Test
    public void testPerm() {

        Subject subject = login("test", "123");

        Assert.assertTrue(subject().isPermitted("custom:perm"));

        //验证失败会抛异常
        //subject().checkPermission("role1");

        //退出
        subject.logout();
    }

    private Subject login(String username, String password){

        //创建SecurityManager实例,配置realm
        org.apache.shiro.mgt.SecurityManager securityManager = new DefaultSecurityManager();
        Realm realm = new MyRealm1();
        ((DefaultSecurityManager) securityManager).setRealm(realm);

        //绑定SecurityManager给SecurityUtils
        SecurityUtils.setSecurityManager(securityManager);

        //得到Subject
        Subject subject = SecurityUtils.getSubject();

        //创建用户名/密码身份验证Token(即用户身份/凭证)
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        try {
            //登录,即身份验证
            subject.login(token);
        } catch (AuthenticationException e) {
            //身份验证失败处理
            e.printStackTrace();
        }

        //断言用户已经登录
        Assert.assertEquals(true, subject.isAuthenticated());

        return subject;
    }

下面是MyRealm1类

public class MyRealm1 extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        String username = (String)principals.getPrimaryPrincipal();

        //模拟根据不同用户名获取不同的角色和权限
        String userRole = "";
        List<String> userPerms = new ArrayList<>();
        if ("test".equals(username)){
            userRole = "custom";
            userPerms.add("custom:perm");
        } else if ("admin".equals(username)){
            userRole = "admin";
            userPerms.add("admin:perm");
        }

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addRole(userRole);
        authorizationInfo.addStringPermissions(userPerms);

        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        String username = (String)token.getPrincipal();  //得到用户名
        String password = new String((char[])token.getCredentials()); //得到密码

        if(!"test".equals(username) && !"admin".equals(username)) {
            throw new UnknownAccountException(); //如果用户名错误
        }
        if(!"123".equals(password)) {
            throw new IncorrectCredentialsException(); //如果密码错误
        }

        //如果身份认证验证成功,返回一个AuthenticationInfo实现;
        return new SimpleAuthenticationInfo(username, password, getName());
    }
}

 

1.角色验证

 

//DelegatingSubject 第223行

    public boolean hasRole(String roleIdentifier) {
        return hasPrincipals() && securityManager.hasRole(getPrincipals(), roleIdentifier);
    }
//AuthorizingSecurityManager 第152行

   public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
        //SecurityManager 调用Authorizer
        return this.authorizer.hasRole(principals, roleIdentifier);
    }
//AuthorizingRealm 第570行

    public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {
        AuthorizationInfo info = getAuthorizationInfo(principal);
        return hasRole(roleIdentifier, info);
    }


// AuthorizingRealm 第310行
    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 
//调用子类doGetAuthrizationInfo方法(参照前面MyRealm1)
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; }
//AuthorizingRealm 第575行
    protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
        return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
    }

角色验证,这里只分析了hasRole方法,checkRole方法与之类似,不同的是验证失败会抛出异常。

总结一下角色验证过程

(1)用户程序调用subject.hasRole(roleString)

(2)subject调用SecurityManager的hasRole方法

(3)SecurityManager通过Authorizer的hasRole方法验证是否拥有角色

(4)Authorizer类hasRole方法内通过AuthorizingRealm的getAuthorizationInfo获取角色信息

(5)AuthorizingRealm最后通过调用子类的doGetAuthrizationInfo获取用户角色集合,在通过集合的contains方法判断角色。

 

2.权限验证

todo

posted @ 2021-11-29 22:55  OUYM  阅读(167)  评论(0编辑  收藏  举报