前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Shiro系列 | 《Shiro开发详细教程》第三章:Shiro授权流程-下

Shiro系列 | 《Shiro开发详细教程》第三章:Shiro授权流程-下

作者头像
码神联盟
发布2018-12-05 14:51:18
1.1K0
发布2018-12-05 14:51:18
举报
文章被收录于专栏:码神联盟

本文目录:

► 第三章: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”等。

  • 即*可以匹配所有,不加*可以进行前缀匹配;
  • 但是如“*:view”不能匹配“user:view”,需要使用“*:*:view”;
  • 即后缀匹配必须指定前缀(多个冒号就需要多个*来匹配)。

7. WhildcardPermission

如下两种方式是等价的:

subject.checkPermission("menu:view:1");

subject.checkPermission(new WildcardPermission("menu:view:1"));

8. 性能问题

通配符匹配方式比字符串相等匹配来说是更复杂的,因此需要花费更长时间,但是一般系统的权限不会太多,且可以配合缓存来提供其性能,如果这样性能还达不到要求我们可以实现位操作算法实现性能更好的权限匹配。另外实例级别的权限验证如果数据量太大也不建议使用,可能造成查询权限及匹配变慢。可以考虑比如在sql查询时加上权限字符串之类的方式在查询时就完成了权限匹配。

3.5 授权流程

流程如下:

  • 首先调用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,其流程是:

  • 如果调用 hasRole*,则直接获取 AuthorizationInfo.getRoles() 与传入的角色比较即可;首先如果调用如 isPermitted(“user:view”),首先通过 PermissionResolver 将权限字符串转换成相应的 Permission 实例,默认使用 WildcardPermissionResolver,即转换为通配符的 WildcardPermission;
  • 通过 AuthorizationInfo.getObjectPermissions() 得到 Permission 实例集合;通过 AuthorizationInfo.getStringPermissions() 得到字符串集合并通过 PermissionResolver 解析为 Permission 实例;然后获取用户的角色,并通过 RolePermissionResolver 解析角色对应的权限集合(默认没有实现,可以自己提供);
  • 接着调用 Permission.implies(Permission p) 逐个与传入的权限比较,如果有匹配的则返回 true,否则 false。

Authorizer、PermissionResolver及RolePermissionResolver:

Authorizer 的职责是进行授权(访问控制),是 Shiro API 中授权核心的入口点,其提供了相应的角色/权限判断接口,具体请参考其 Javadoc。SecurityManager 继承了 Authorizer 接口,且提供了 ModularRealmAuthorizer 用于多 Realm 时的授权匹配。

PermissionResolver 用于解析权限字符串到 Permission 实例。

RolePermissionResolver 用于根据角色解析相应的权限集合。

我们可以通过如下 ini 配置更改 Authorizer 实现:

代码语言:javascript
复制
authorizer=org.apache.shiro.authz.ModularRealmAuthorizer
securityManager.authorizer=$authorizer

对于 ModularRealmAuthorizer,相应的 AuthorizingSecurityManager 会在初始化完成后自动将相应的 realm 设置进去,我们也可以通过调用其 setRealms() 方法进行设置。对于实现自己的 authorizer 可以参考 ModularRealmAuthorizer 实现即可。

设置 ModularRealmAuthorizer 的 permissionResolver,其会自动设置到相应的 Realm 上(其实现了 PermissionResolverAware 接口),如:

代码语言:javascript
复制
permissionResolver=org.apache.shiro.authz.permission.WildcardPermissionResolver
authorizer.permissionResolver=$permissionResolver

设置 ModularRealmAuthorizer 的 rolePermissionResolver,其会自动设置到相应的 Realm 上(其实现了 RolePermissionResolverAware 接口),如:

代码语言:javascript
复制
rolePermissionResolver=com.ms.MyRolePermissionResolver
authorizer.rolePermissionResolver=$rolePermissionResolver

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-10-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码神联盟 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档