本文目录:
► 第三章:Shiro授权-下
► 3.4 Permission
► 3.5 授权流程
下节预告
► 第四章:Shiro中Ini配置(预告)
► 4.1 SecurityManger根对象(预告)
► 4.2 ini配置(预告)
3.4 Permission
字符串通配符权限:
规则:资源标识符:操作:对象实例ID
注:即对哪个资源的哪个实例可以进行什么操作
其默认支持通配符权限字符串:
“:”表示资源/操作/实例的分割;
“,”表示操作的分割;
“*” 表示任意资源/操作/实例。
1. 单个资源、单个权限
subject.checkPermissions("user:update");
2. 单个资源,多个权限
ini配置文件:
role4=user:update,user:delete
然后通过如下代码判断:
subject.checkPermissions("user:update", "user:delete");
用户拥有资源“user”的“update”和“delete”权限,可以简写为:
ini 配置(表示角色4拥有user 资源的 update 和 delete 权限)
role4="user:update,delete"
接着可以通过如下代码判断
subject.checkPermissions("user:update,delete");
通过“user:update,delete”验证“user:update,user:delete”是没问题的,但是反过来是规则不成立。
3. 单个资源、全部权限
Ini配置:
role5="user:create,update,delete,view"
然后通过如下代码判断:
subject.checkPermissions("user:create,delete,update:view");
用户拥有资源“user”的“create”、“update”、“delete”和“view”所有权限。
如上可以简写成:
ini 配置文件(表示角色 5 拥有user 的所有权限)
role5=user:*
也可以简写为(推荐上边的写法):
role5=user
然后通过如下代码判断:
subject.checkPermissions("user:*"); subject.checkPermissions("user");
通过“user:*”验证“user:create,delete,update:view”可以,但是反过来是不成立的。
4. 所有资源、全部权限
ini 配置:
role6=*:view
然后通过如下代码判断:
subject.checkPermissions("user:view");
用户拥有所有资源的“view”所有权限。假设判断的权限是“"user:view”,那么需要“role6=::view”这样写才行。
5. 实例级别的权限
a) 单个实例、单个权限
ini 配置:
role7=user:view:1
对资源 user 的 1 实例拥有 view 权限。
然后通过如下代码判断:
subject.checkPermissions("user:view:1");
b) 单个实例、多个权限
ini 配置:
role7="user:update,delete:1"
对资源 user 的 1 实例拥有 update、delete 权限。
然后通过如下代码判断 :
subject.checkPermissions("user:delete,update:1");
subject.checkPermissions("user:update:1", "user:delete:1");
c) 单个实例、所有权限
ini 配置:
role7=user:*:1
对资源 user 的 1 实例拥有所有权限。
然后通过如下代码判断:
subject.checkPermissions("user:update:1","user:delete:1","user:view:1");
d) 所有实例、单个权限
ini 配置:
role7=user:auth:*
对资源 user 的 1 实例拥有所有权限。
然后通过如下代码判断:
subject.checkPermissions("user:auth:1", "user:auth:2");
e) 所有实例、所有权限
ini 配置:
role7=user:*:*
对资源 user 的 1 实例拥有所有权限。
然后通过如下代码判断:
subject.checkPermissions("user:view:1", "user:auth:2");
6. Shiro对权限字符串缺失部分的处理
如“user:view”等价于“user:view:*”;
而“organization”等价于“organization:*”或者“organization:*:*”。
可以这么理解,这种方式实现了前缀匹配。
另外如:
“user:*”可以匹配如“user:delete”
“user:delete”可以匹配如“user:delete:1”
“user:*:1”可以匹配如“user:view:1”、
“user”可以匹配”user:view”或“user:view:1”等。
7. WhildcardPermission
如下两种方式是等价的:
subject.checkPermission("menu:view:1");
subject.checkPermission(new WildcardPermission("menu:view:1"));
8. 性能问题
通配符匹配方式比字符串相等匹配来说是更复杂的,因此需要花费更长时间,但是一般系统的权限不会太多,且可以配合缓存来提供其性能,如果这样性能还达不到要求我们可以实现位操作算法实现性能更好的权限匹配。另外实例级别的权限验证如果数据量太大也不建议使用,可能造成查询权限及匹配变慢。可以考虑比如在sql查询时加上权限字符串之类的方式在查询时就完成了权限匹配。
3.5 授权流程
流程如下:
ModularRealmAuthorizer 进行多 Realm 匹配流程:
如果 Realm 进行授权的话,应该继承 AuthorizingRealm,其流程是:
Authorizer、PermissionResolver及RolePermissionResolver:
Authorizer 的职责是进行授权(访问控制),是 Shiro API 中授权核心的入口点,其提供了相应的角色/权限判断接口,具体请参考其 Javadoc。SecurityManager 继承了 Authorizer 接口,且提供了 ModularRealmAuthorizer 用于多 Realm 时的授权匹配。
PermissionResolver 用于解析权限字符串到 Permission 实例。
RolePermissionResolver 用于根据角色解析相应的权限集合。
我们可以通过如下 ini 配置更改 Authorizer 实现:
authorizer=org.apache.shiro.authz.ModularRealmAuthorizer
securityManager.authorizer=$authorizer
对于 ModularRealmAuthorizer,相应的 AuthorizingSecurityManager 会在初始化完成后自动将相应的 realm 设置进去,我们也可以通过调用其 setRealms() 方法进行设置。对于实现自己的 authorizer 可以参考 ModularRealmAuthorizer 实现即可。
设置 ModularRealmAuthorizer 的 permissionResolver,其会自动设置到相应的 Realm 上(其实现了 PermissionResolverAware 接口),如:
permissionResolver=org.apache.shiro.authz.permission.WildcardPermissionResolver
authorizer.permissionResolver=$permissionResolver
设置 ModularRealmAuthorizer 的 rolePermissionResolver,其会自动设置到相应的 Realm 上(其实现了 RolePermissionResolverAware 接口),如:
rolePermissionResolver=com.ms.MyRolePermissionResolver
authorizer.rolePermissionResolver=$rolePermissionResolver