【Shiro学习之三】权限验证
Apache shiro:1.6.0
一、重要组件
1、Authorizer 的职责是进行授权(访问控制),是 Shiro API 中授权核心的入口点,其提供了相应的角色/权限判断接口,具体协调realm验证权限是在ModularRealmAuthorizer里进行。
2、PermissionResolver接口用于解析权限字符串到WildcardPermission实例,默认实现WildcardPermissionResolver;RolePermissionResolver接口用于根据角色解析相应的权限集合。
3、AuthorizationInfo
public interface AuthorizationInfo extends Serializable { Collection<String> getRoles(); //获取角色字符串信息 Collection<String> getStringPermissions(); //获取权限字符串信息 Collection<Permission> getObjectPermissions(); //获取 Permission 对象信息 }
AuthorizationInfo 用于聚合授权信息的,当我们使用AuthorizingRealm 时, 如果身份验证成功, 在进行授权时就通过doGetAuthorizationInfo 方法获取角色/权限信息用于授权验证。
Shiro提供了一个实现 SimpleAuthorizationInfo,大多数时候使用这个即可
二、权限验证流程
1、代码示例
(1)角色验证
@Test public void testHasRole() { login("classpath:shiro-role.ini", "zhang", "123"); //判断拥有角色:role1 Assert.assertTrue(subject().hasRole("role1")); //判断拥有角色:role1 and role2 Assert.assertTrue(subject().hasAllRoles(Arrays.asList("role1", "role2"))); //判断拥有角色:role1 and role2 and !role3 boolean[] result = subject().hasRoles(Arrays.asList("role1", "role2", "role3")); Assert.assertEquals(true, result[0]); Assert.assertEquals(true, result[1]); Assert.assertEquals(false, result[2]); }
(2)权限验证
@Test public void testIsPermitted() { login("classpath:shiro-permission.ini", "zhang", "123"); //判断拥有权限:user:create Assert.assertTrue(subject().isPermitted("user:create")); //判断拥有权限:user:update and user:delete Assert.assertTrue(subject().isPermittedAll("user:update", "user:delete")); //判断没有权限:user:view Assert.assertFalse(subject().isPermitted("user:view")); }
2、图示流程
流程如下: (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 表示授权失败。
3、源码流程分析
角色验证:
Subject::hasRole -->DelegatingSubject::hasRole -->securityManager::hasRole -->AuthorizingSecurityManager::hasRole -->ModularRealmAuthorizer::hasRole 在这里会获取所有的realm,调用realm的doGetAuthorizationInfo进行获取权限信息AuthorizationInfo -->然后AuthorizationInfo调用getRoles()获取所有角看是否包含指定的角色; ModularRealmAuthorizer 进行多 Realm 匹配流程: (1)首先检查相应的Realm是否实现了实现了 Authorizer; (2)如果实现了Authorizer,那么接着调用其相应的isPermitted*/hasRole*接口进行匹配; (3)如果有一个Realm匹配那么将返回true 否则返回 false。
权限验证:
Subject::isPermitted -->DelegatingSubject::isPermitted -->securityManager::isPermitted -->AuthorizingSecurityManager::isPermitted -->ModularRealmAuthorizer::isPermitted -->AuthorizingRealm::isPermitted 首先通过 PermissionResolver 将权限字符串转换成相应的 Permission 实例,默认使用 WildcardPermissionResolver,即转换为通配符的WildcardPermission; 然后和realm的doGetAuthorizationInfo获取的权限信息AuthorizationInfo,获得所有权限集合,然后循环比对。
学习技术不是用来写HelloWorld和Demo的,而是要用来解决线上系统的真实问题的.