Shiro之授权流程篇

授权流程

授权的入口有两种,第一种通过拦截器,第二种是注解
首先看下默认的拦截器

public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    authcBearer(BearerHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class),
    invalidRequest(InvalidRequestFilter.class);
    ...
}

查看RolesAuthorizationFilter.class

...
public class RolesAuthorizationFilter extends AuthorizationFilter {
    public RolesAuthorizationFilter() {
    }

    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
    	// 获取Subject对象
        Subject subject = this.getSubject(request, response);
        String[] rolesArray = (String[])mappedValue;
        if (rolesArray != null && rolesArray.length != 0) {
            Set<String> roles = CollectionUtils.asSet(rolesArray);
            // 通过subject.hasAllRoles(roles)来验证角色
            return subject.hasAllRoles(roles);
        } else {
            return true;
        }
    }
}

再来看下注解的RequiresRoles 、以及对应的AOP处理

package org.apache.shiro.authz.annotation;
...
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresRoles {
    String[] value();

    Logical logical() default Logical.AND;
}

package org.apache.shiro.authz.aop;
...
public class RoleAnnotationHandler extends AuthorizingAnnotationHandler {
    public RoleAnnotationHandler() {
        super(RequiresRoles.class);
    }

    public void assertAuthorized(Annotation a) throws AuthorizationException {
        if (a instanceof RequiresRoles) {
            RequiresRoles rrAnnotation = (RequiresRoles)a;
            String[] roles = rrAnnotation.value();
            if (roles.length == 1) {
            	// getSubject()就是获取Subject对象
                this.getSubject().checkRole(roles[0]);
            } else if (Logical.AND.equals(rrAnnotation.logical())) {
                this.getSubject().checkRoles(Arrays.asList(roles));
            } else {
                if (Logical.OR.equals(rrAnnotation.logical())) {
                    boolean hasAtLeastOneRole = false;
                    String[] var5 = roles;
                    int var6 = roles.length;

                    for(int var7 = 0; var7 < var6; ++var7) {
                        String role = var5[var7];
                        // 等同于 subject.hasRole(role)
                        if (this.getSubject().hasRole(role)) {
                            hasAtLeastOneRole = true;
                        }
                    }

                    if (!hasAtLeastOneRole) {
                        this.getSubject().checkRole(roles[0]);
                    }
                }

            }
        }
    }
}

通过上面两种方式,我们知道正真授权的是Subject对象,而它是一个接口,由子类DelegatingSubject 实现

...
public class DelegatingSubject implements Subject {

    public boolean isPermitted(String permission) {
        return this.hasPrincipals() && this.securityManager.isPermitted(this.getPrincipals(), permission);
    }

    public boolean isPermitted(Permission permission) {
        return this.hasPrincipals() && this.securityManager.isPermitted(this.getPrincipals(), permission);
    }

    public boolean[] isPermitted(String... permissions) {
        return this.hasPrincipals() ? this.securityManager.isPermitted(this.getPrincipals(), permissions) : new boolean[permissions.length];
    }

    public boolean[] isPermitted(List<Permission> permissions) {
        return this.hasPrincipals() ? this.securityManager.isPermitted(this.getPrincipals(), permissions) : new boolean[permissions.size()];
    }

    public boolean isPermittedAll(String... permissions) {
        return this.hasPrincipals() && this.securityManager.isPermittedAll(this.getPrincipals(), permissions);
    }

    public boolean isPermittedAll(Collection<Permission> permissions) {
        return this.hasPrincipals() && this.securityManager.isPermittedAll(this.getPrincipals(), permissions);
    }

    public void checkPermission(String permission) throws AuthorizationException {
        this.assertAuthzCheckPossible();
        this.securityManager.checkPermission(this.getPrincipals(), permission);
    }

    public void checkPermission(Permission permission) throws AuthorizationException {
        this.assertAuthzCheckPossible();
        this.securityManager.checkPermission(this.getPrincipals(), permission);
    }

    public void checkPermissions(String... permissions) throws AuthorizationException {
        this.assertAuthzCheckPossible();
        this.securityManager.checkPermissions(this.getPrincipals(), permissions);
    }

    public void checkPermissions(Collection<Permission> permissions) throws AuthorizationException {
        this.assertAuthzCheckPossible();
        this.securityManager.checkPermissions(this.getPrincipals(), permissions);
    }

    public boolean hasRole(String roleIdentifier) {
        return this.hasPrincipals() && this.securityManager.hasRole(this.getPrincipals(), roleIdentifier);
    }

    public boolean[] hasRoles(List<String> roleIdentifiers) {
        return this.hasPrincipals() ? this.securityManager.hasRoles(this.getPrincipals(), roleIdentifiers) : new boolean[roleIdentifiers.size()];
    }

    public boolean hasAllRoles(Collection<String> roleIdentifiers) {
        return this.hasPrincipals() && this.securityManager.hasAllRoles(this.getPrincipals(), roleIdentifiers);
    }

    public void checkRole(String role) throws AuthorizationException {
        this.assertAuthzCheckPossible();
        this.securityManager.checkRole(this.getPrincipals(), role);
    }

    public void checkRoles(String... roleIdentifiers) throws AuthorizationException {
        this.assertAuthzCheckPossible();
        this.securityManager.checkRoles(this.getPrincipals(), roleIdentifiers);
    }

    public void checkRoles(Collection<String> roles) throws AuthorizationException {
        this.assertAuthzCheckPossible();
        this.securityManager.checkRoles(this.getPrincipals(), roles);
    }

    public boolean isAuthenticated() {
        return this.authenticated;
    }

    public boolean isRemembered() {
        PrincipalCollection principals = this.getPrincipals();
        return principals != null && !principals.isEmpty() && !this.isAuthenticated();
    }
}

查看hasRole,发现授权委托给了securityManager,而securityManager委托给了Authorizer

    public boolean hasRole(String roleIdentifier) {
        return this.hasPrincipals() && this.securityManager.hasRole(this.getPrincipals(), roleIdentifier);
    }

Authorizer 由 子类 ModularRealmAuthorizer 实现

public class ModularRealmAuthorizer implements Authorizer, PermissionResolverAware, RolePermissionResolverAware {
    ...
    public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
        this.assertRealmsConfigured();
        Iterator var3 = this.getRealms().iterator();

        Realm realm;
        // 遍历所有的Realm
        do {
            if (!var3.hasNext()) {
                return false;
            }

            realm = (Realm)var3.next();
            // 再次调用hasRole,这次是由 Authorizer的另一个子类AuthorizingRealm实现的
        } while(!(realm instanceof Authorizer) || !((Authorizer)realm).hasRole(principals, roleIdentifier));

        return true;
    }
    ...
}

Authorizer的另一个子类AuthorizingRealm

public abstract class AuthorizingRealm extends AuthenticatingRealm implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware {
    ...
    public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {
    	// 获取AuthorizationInfo授权对象
        AuthorizationInfo info = this.getAuthorizationInfo(principal);
        return this.hasRole(roleIdentifier, info);
    }

	protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            return null;
        } else {
            AuthorizationInfo info = null;
            if (log.isTraceEnabled()) {
                log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");
            }
			// 先从缓存获取授权对象
            Cache<Object, AuthorizationInfo> cache = this.getAvailableAuthorizationCache();
            Object key;
            if (cache != null) {
               	...
            }

            if (info == null) {
            	// 缓存没有,调用自身doGetAuthorizationInfo抽象方法
                info = this.doGetAuthorizationInfo(principals);
                ...
            }

            return info;
        }
    }

	// 该方法是由我们自定义的Realm实现的
	protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1);
	...
}

doGetAuthorizationInfo()抽象方法就是我们自定义Realm里面实现的授权方法,返回具体角色信息和权限信息的 AuthorizationInfo 授权对象

...
public class MyShiroRealm extends AuthorizingRealm {
	...
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    /**
     * 授权方法
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = (String) principalCollection.getPrimaryPrincipal();
        // 查询用户,获取角色ids
        User user = userService.lambdaQuery().eq(User::getUsername, username).one();
        List<Integer> roleIds = Arrays.stream(user.getRIds().split(","))
                .map(Integer::parseInt)
                .collect(Collectors.toList());

        // 查询角色,获取角色名、权限ids
        List<Role> roles = roleService.listByIds(roleIds);
        Set<String> roleNames = new HashSet<>(roles.size());
        Set<Integer> permIds = new HashSet<>();
        roles.forEach(role -> {
            roleNames.add(role.getRName());
            Set<Integer> collect = Arrays.stream(
                    role.getPIds().split(",")).map(Integer::parseInt).collect(Collectors.toSet());
            permIds.addAll(collect);
        });

        // 获取权限名称
        List<Permissions> permissions = permissionsService.listByIds(permIds);
        List<String> permNames = permissions.stream().map(Permissions::getPName).collect(Collectors.toList());

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addRoles(roleNames);
        authorizationInfo.addStringPermissions(permNames);
        return authorizationInfo;
    }

    /**
     * 认证方法
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        ...
    }
}

AuthorizingRealm#hasRole 获取到授权对象之后,调用自身的hasRole()方法

  	public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {
    	// 获取AuthorizationInfo授权对象
        AuthorizationInfo info = this.getAuthorizationInfo(principal);
        return this.hasRole(roleIdentifier, info);
   }

	// 返回true,则允许访问
	protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
       return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
   }
  

测试

definitionMap.put("/admin/**", "roles[ADMIN]");

1.登录yzm,访问/admin
2.来到roles过滤器,subject.hasAllRoles(roles)
在这里插入图片描述

3.DelegatingSubject#hasAllRoles
在这里插入图片描述

4 ModularRealmAuthorizer#hasAllRoles 调用自身this.hasRole(principals, roleIdentifier)
在这里插入图片描述
在这里插入图片描述

5 AuthorizingRealm#hasRole、getAuthorizationInfo
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6 自定义的MyShiroRealm
在这里插入图片描述

7 组装好角色权限信息返回AuthorizationInfo对象给AuthorizingRealm
在这里插入图片描述

相关链接

首页
上一篇:认证流程篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值