基于角色的访问控制(隐式角色)
1、在ini配置文件配置用户拥有的角色(shiro-role.ini)
[users] zhang=123,role1,role2 wang=123,role1
规则即:“用户名=密码,角色1,角色2”,如果需要在应用中判断用户是否有相应角色,就需要在相应的Realm中返回角色信息,也就是说Shiro不负责维护用户-角色信息,需要应用提供,Shiro只是提供相应的接口方便验证,后续会介绍如何动态的获取用户角色。
2、测试用例(com.github.zhangkaitao.shiro.chapter3.RoleTest)
@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]); }
Shiro
提供了hasRole/hasRole
用于判断用户是否拥有某个角色/某些权限;但是没有提供如hashAnyRole
用于判断是否有某些权限中的某一个。
@Test(expected = UnauthorizedException.class) public void testCheckRole() { login("classpath:shiro-role.ini", "zhang", "123"); //断言拥有角色:role1 subject().checkRole("role1"); //断言拥有角色:role1 and role3 失败抛出异常 subject().checkRoles("role1", "role3"); }
Shiro提供的checkRole/checkRoles
和hasRole/hasAllRoles
不同的地方是它在判断为假的情况下会抛出UnauthorizedException异常
。
到此基于角色的访问控制(即隐式角色)就完成了,这种方式的缺点就是如果很多地方进行了角色判断,但是有一天不需要了那么就需要修改相应代码把所有相关的地方进行删除;这就是粗粒度造成的问题。
基于资源的访问控制(显示角色)
1、在ini配置文件配置用户拥有的角色及角色-权限关系(shiro-permission.ini)
[users] zhang=123,role1,role2 wang=123,role1 [roles] role1=user:create,user:update role2=user:create,user:delete
规则:“用户名=密码,角色1,角色2”“角色=权限1,权限2”,即首先根据用户名找到角色,然后根据角色再找到权限;即角色是权限集合;Shiro同样不进行权限的维护,需要我们通过Realm返回相应的权限信息。只需要维护“用户——角色”之间的关系即可。
2、测试用例(com.github.zhangkaitao.shiro.chapter3.PermissionTest)
@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")); }
Shiro提供了isPermitted
和isPermittedAll
用于判断用户是否拥有某个权限或所有权限,也没有提供如isPermittedAny
用于判断拥有某一个权限的接口。
@Test(expected = UnauthorizedException.class) public void testCheckPermission () { login("classpath:shiro-permission.ini", "zhang", "123"); //断言拥有权限:user:create subject().checkPermission("user:create"); //断言拥有权限:user:delete and user:update subject().checkPermissions("user:delete", "user:update"); //断言拥有权限:user:view 失败抛出异常 subject().checkPermissions("user:view"); }
但是失败的情况下会抛出UnauthorizedException异常。
到此基于资源的访问控制(显示角色)就完成了,也可以叫基于权限的访问控制,这种方式的一般规则是“资源标识符:操作”,即是资源级别的粒度;这种方式的好处就是如果要修改基本都是一个资源级别的修改,不会对其他模块代码产生影响,粒度小。但是实现起来可能稍微复杂点,需要维护“用户——角色,角色——权限(资源:操作)”之间的关系。