内容简介:上一节我们讲了自定义Realm中的认证(流程如下:ModularRealmAuthorizer进行多Realm匹配流程:
上一节我们讲了自定义Realm中的认证( doGetAuthenticationInfo ),这节我们继续讲另一个方法 doGetAuthorizationInfo 授权
授权流程
流程如下:
- 首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager,而SecurityManager接着会委托给 Authorizer ;
- Authorizer 是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;
- 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;
- Authorizer 会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如isPermitted*/hasRole*会返回true,否则返回false表示授权失败。
ModularRealmAuthorizer进行多Realm匹配流程:
- 首先检查相应的Realm是否实现了实现了Authorizer;
- 如果实现了Authorizer,那么接着调用其相应的isPermitted*/hasRole*接口进行匹配;
- 如果有一个Realm匹配那么将返回true,否则返回false。
如果Realm进行授权的话,应该继承 AuthorizingRealm ,其流程是:
1.1、如果调用hasRole,则直接获取AuthorizationInfo.getRoles()与传入的角色比较即可;
1.2、首先如果调用如isPermitted(“user:view”),首先通过PermissionResolver将权限字符串转换成相应的Permission实例,默认使用WildcardPermissionResolver,即转换为通配符的WildcardPermission;
2、通过AuthorizationInfo.getObjectPermissions()得到Permission实例集合;通过AuthorizationInfo. getStringPermissions()得到字符串集合并通过PermissionResolver解析为Permission实例;然后获取用户的角色,并通过RolePermissionResolver解析角色对应的权限集合(默认没有实现,可以自己提供);
3、接着调用Permission. implies(Permission p)逐个与传入的权限比较,如果有匹配的则返回true,否则false。
先看一段简单的授权方法重写
@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
因为我们可以在Shiro中同时配置多个Realm,所以呢身份信息可能就有多个;因此其提供了PrincipalCollection用于聚合这些身份信息:
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。
AuthorizationInfo
AuthorizationInfo用于聚合授权信息的:
public interface AuthorizationInfo extends Serializable {
Collection<String> getRoles(); //获取角色字符串信息
Collection<String> getStringPermissions(); //获取权限字符串信息
Collection<Permission> getObjectPermissions(); //获取Permission对象信息
}
复制代码
当我们使用AuthorizingRealm时,如果身份验证成功,在进行授权时就通过doGetAuthorizationInfo方法获取角色/权限信息用于授权验证。 Shiro提供了一个实现SimpleAuthorizationInfo,大多数时候使用这个即可。
我们再跟踪一下代码,看看是如何调用 Authorizer 的
subject.hasRole("admin")
复制代码
- 调用DelegatingSubject类的hasRole方法
public boolean hasRole(String roleIdentifier) {
return hasPrincipals() && securityManager.hasRole(getPrincipals(), roleIdentifier);
}
复制代码
- 调用AuthorizingSecurityManager的hasRole
public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
return this.authorizer.hasRole(principals, roleIdentifier);
}
复制代码
- AuthorizingSecurityManager类在创建的时候就注入了ModularRealmAuthorizer类为authorizer
public AuthorizingSecurityManager() {
super();
this.authorizer = new ModularRealmAuthorizer();
}
复制代码
- 继续跟进到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;
}
复制代码
- 此处的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;
}
复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 【官方授权】2018 秋季伯克利大学 CS 294-112 《深度强化学习》学习小组成员招募
- ASP.NET Core分布式项目实战(详解oauth2授权码流程)--学习笔记
- 认证授权方案之授权揭秘 (上篇)
- 013.Kubernetes认证授权
- Redis未授权访问
- 微信网页授权
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Mathematica Cookbook
Sal Mangano / O'Reilly Media / 2009 / GBP 51.99
As the leading software application for symbolic mathematics, Mathematica is standard in many environments that rely on math, such as science, engineering, financial analysis, software development, an......一起来看看 《Mathematica Cookbook》 这本书的介绍吧!