内容简介:上一节我们讲了自定义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未授权访问
- 微信网页授权
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript and Ajax for the Web, Sixth Edition
Tom Negrino、Dori Smith / Peachpit Press / August 28, 2006 / $24.99
Book Description Need to learn JavaScript fast? This best-selling reference’s visual format and step-by-step, task-based instructions will have you up and running with JavaScript in no time. In thi......一起来看看 《JavaScript and Ajax for the Web, Sixth Edition》 这本书的介绍吧!