上一节我们讲了自定义Realm中的认证(doGetAuthenticationInfo),这节我们继续讲另一个方法doGetAuthorizationInfo授权

授权流程

流程如下:

  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表示授权失败。

ModularRealmAuthorizer进行多Realm匹配流程:

  1. 首先检查相应的Realm是否实现了实现了Authorizer;
  2. 如果实现了Authorizer,那么接着调用其相应的isPermitted*/hasRole*接口进行匹配;
  3. 如果有一个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。


先看一段简单的授权方法重写

    @Overrideprotected 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")
复制代码
  1. 调用DelegatingSubject类的hasRole方法
    public boolean hasRole(String roleIdentifier) {return hasPrincipals() && securityManager.hasRole(getPrincipals(), roleIdentifier);}
复制代码
  1. 调用AuthorizingSecurityManager的hasRole
 public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {return this.authorizer.hasRole(principals, roleIdentifier);}
复制代码
  1. AuthorizingSecurityManager类在创建的时候就注入了ModularRealmAuthorizer类为authorizer
    public AuthorizingSecurityManager() {super();this.authorizer = new ModularRealmAuthorizer();}
复制代码
  1. 继续跟进到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;}
复制代码
  1. 此处的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-332protected 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;}
复制代码

SpringBoot+Shiro学习(四):Realm授权相关推荐

  1. SpringBoot+Shiro学习(一):主要模块介绍

    这篇文章是我最近对SpringBoot+Shiro+mybatis+redis一个练手项目的记录. 我是按照慕课网的一篇课程+百度进行练手的 慕课课程 练手项目Github地址 跟着开涛学Shiro ...

  2. SpringBoot+Shiro学习(八):RememberMe

    这一章比较简单,就不多说了,上代码: /** * cookie对象; * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cookie的有效时间等等. ...

  3. shiro 学习(一)

    title: shiro学习(一) date: 2020-11-13 tags: spring springboot shiro categories: spring springboot shiro ...

  4. Shiro学习笔记_02:shiro的认证+shiro的授权

    Shiro 学习笔记 本文基于B站UP主[编程不良人]视频教程[2020最新版Shiro教程,整合SpringBoot项目实战教程]进行整理记录,仅用于个人学习交流使用. 视频链接:https://w ...

  5. SpringBoot整合Shiro学习(上)

    SpringBoot整合Shiro(上) 基于[编程不良人]2020最新版Shiro教程,整合SpringBoot项目实战教程 哔哩哔哩链接:https://www.bilibili.com/vide ...

  6. 单realm模式下前后端分离实现springboot+shiro+jwt+vue整合

    shiro+jwt实现前后端分离 一.RBAC概念 基于角色的权限访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注.在R ...

  7. Day374.shiro授权Shiro+jsp整合Springboot -Shiro

    Shiro授权 一.授权 授权,即访问控制,控制谁能访问哪些资源.主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的. 二.关键对象 授权可简单理解为who对what( ...

  8. authc过滤器 shiro_使用Shiro实现认证和授权(基于SpringBoot)

    Apache Shiro是一个功能强大且易于使用的Java安全框架,它为开发人员提供了一种直观,全面的身份验证,授权,加密和会话管理解决方案.下面是在SpringBoot中使用Shiro进行认证和授权 ...

  9. [shiro学习笔记]第二节 shiro与web融合实现一个简单的授权认证

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/39933993 shiro官网: http://shiro.apache.org/ sh ...

最新文章

  1. photoshop 图片转 pdf
  2. 解决Moodle日历乱码的最佳方案
  3. mac Hbuilder 无法打开的解决方案
  4. 命名空间“Microsoft.Office”中不存在类型或命名空间名称“Interop”(是否缺少程序集引用?...
  5. Java基础——Java IO详解
  6. nginx作为静态资源服务器的配置
  7. ORA-01075: you are currently logged on
  8. ThinkPHP添加谷歌验证码验证
  9. 荣耀路由2 虚拟服务器,荣耀路由器2恢复出厂设置的两种方法
  10. android 比较全的android 源码合集 + 企业级应用分享,从业的积累(加强版)
  11. 提高DevExpress winform 控件加载速度
  12. [爬虫] Python监测L优惠券发放网站并通过邮件通知我
  13. 大学物理实验计算机仿真 光电效应,大学物理实验报告模版
  14. 为OneFlow添加新的前端语言
  15. 转:长篇小说《七月七日晴》(超感人的)(上)
  16. Java核心编程随笔
  17. php框架标签,CMF5自定义标签
  18. c语言fopen错误指针,fopen出错的原因
  19. OpenCV的Scalar对象怎样初始化,如何取分量值,如何与标量相乘?
  20. 中国现代书画家——谭奇中、李义象、高俊鹏等

热门文章

  1. java GUI怎么输入_在Swing中创建Java GUI以进行表单输入
  2. 问题反馈模板_使用此模板可获得更好,更有价值的UX反馈
  3. Android Studio中解决jar包重复依赖导致的代码编译错误
  4. 【columnstore】mariadb columnstore 数据迁移
  5. MySQL修改字符集
  6. 拉美光伏新兴市场热潮将至
  7. 《网站情感化设计与内容策略》一第1章 情感化设计1.1 革命:有失亦有得
  8. 高可用架构-- MySQL主从复制的配置
  9. Linux操作系统基础解析之(五)——grep命令家族及正则表达式初识
  10. 第二十一章流 5 多种打开文件的方式 文件存在,文件不存在