SpringBoot+Shiro学习(四):Realm受权

上一节咱们讲了自定义Realm中的认证(doGetAuthenticationInfo),这节咱们继续讲另外一个方法doGetAuthorizationInfo受权数据库

受权流程

image

流程以下:bash

  1. 首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer
  2. Authorizer是真正的受权者,若是咱们调用如isPermitted(“user:view”),其首先会经过PermissionResolver把字符串转换成相应的Permission实例;
  3. 在进行受权以前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;
  4. Authorizer会判断Realm的角色/权限是否和传入的匹配,若是有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,若是匹配如isPermitted*/hasRole*会返回true,不然返回false表示受权失败。

ModularRealmAuthorizer进行多Realm匹配流程:ide

  1. 首先检查相应的Realm是否实现了实现了Authorizer;
  2. 若是实现了Authorizer,那么接着调用其相应的isPermitted*/hasRole*接口进行匹配;
  3. 若是有一个Realm匹配那么将返回true,不然返回false。

若是Realm进行受权的话,应该继承AuthorizingRealm,其流程是:
1.一、若是调用hasRole,则直接获取AuthorizationInfo.getRoles()与传入的角色比较便可;
1.二、首先若是调用如isPermitted(“user:view”),首先经过PermissionResolver将权限字符串转换成相应的Permission实例,默认使用WildcardPermissionResolver,即转换为通配符的WildcardPermission;
二、经过AuthorizationInfo.getObjectPermissions()获得Permission实例集合;经过AuthorizationInfo. getStringPermissions()获得字符串集合并经过PermissionResolver解析为Permission实例;而后获取用户的角色,并经过RolePermissionResolver解析角色对应的权限集合(默认没有实现,能够本身提供);
三、接着调用Permission. implies(Permission p)逐个与传入的权限比较,若是有匹配的则返回true,不然false。ui


先看一段简单的受权方法重写this

@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取用户名
        String username = (String) principals.getPrimaryPrincipal();
        //此处从数据库获取该用户的角色
        Set<String> roles = getRolesByUserName(username);
        //此处从数据库获取该角色的权限
        Set<String> permissions = getPermissionsByUserName(username);
        //放到info里返回
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permissions);
        info.setRoles(roles);
        return info;
    }
复制代码

PrincipalCollection

image

由于咱们能够在Shiro中同时配置多个Realm,因此呢身份信息可能就有多个;所以其提供了PrincipalCollection用于聚合这些身份信息:spa

public interface PrincipalCollection extends Iterable, Serializable {  
  Object getPrimaryPrincipal(); //获得主要的身份  
  <T> T oneByType(Class<T> type); //根据身份类型获取第一个  
  <T> Collection<T> byType(Class<T> type); //根据身份类型获取一组  
  List asList(); //转换为List  
  Set asSet(); //转换为Set  
  Collection fromRealm(String realmName); //根据Realm名字获取  
  Set<String> getRealmNames(); //获取全部身份验证经过的Realm名字  
  boolean isEmpty(); //判断是否为空  
}   
复制代码

由于PrincipalCollection聚合了多个,此处最须要注意的是getPrimaryPrincipal,若是只有一个Principal那么直接返回便可,若是有多个Principal,则返回第一个(由于内部使用Map存储,因此能够认为是返回任意一个);oneByType / byType根据凭据的类型返回相应的Principal;fromRealm根据Realm名字(每一个Principal都与一个Realm关联)获取相应的Principal。code

AuthorizationInfo

image

AuthorizationInfo用于聚合受权信息的:cdn

public interface AuthorizationInfo extends Serializable {  
 Collection<String> getRoles(); //获取角色字符串信息  
 Collection<String> getStringPermissions(); //获取权限字符串信息  
 Collection<Permission> getObjectPermissions(); //获取Permission对象信息  
}   
复制代码

当咱们使用AuthorizingRealm时,若是身份验证成功,在进行受权时就经过doGetAuthorizationInfo方法获取角色/权限信息用于受权验证。 Shiro提供了一个实现SimpleAuthorizationInfo,大多数时候使用这个便可。对象


咱们再跟踪一下代码,看看是如何调用Authorizerblog

subject.hasRole("admin")
复制代码
  1. 调用DelegatingSubject类的hasRole方法
public boolean hasRole(String roleIdentifier) {
        return hasPrincipals() && securityManager.hasRole(getPrincipals(), roleIdentifier);
    }
复制代码
  1. 调用AuthorizingSecurityManager的hasRole
public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
        return this.authorizer.hasRole(principals, roleIdentifier);
    }
复制代码
  1. AuthorizingSecurityManager类在建立的时候就注入了ModularRealmAuthorizer类为authorizer
public AuthorizingSecurityManager() {
        super();
        this.authorizer = new ModularRealmAuthorizer();
    }
复制代码
  1. 继续跟进到ModularRealmAuthorizer的hasRole方法
public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
        assertRealmsConfigured();
        for (Realm realm : getRealms()) {
            if (!(realm instanceof Authorizer)) continue;
            if (((Authorizer) realm).hasRole(principals, roleIdentifier)) {
                return true;
            }
        }
        return false;
    }
复制代码
  1. 此处的hasRole是调用AuthorizingRealm抽象类的hasRole方法。同理,isPermitted也是最后调用到此。
public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {
        AuthorizationInfo info = getAuthorizationInfo(principal);
        return hasRole(roleIdentifier, info);
    }

    protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
        return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
    }

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

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

    //changed visibility from private to protected for SHIRO-332
    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;
    }
复制代码
相关文章
相关标签/搜索