【Shiro】Shiro 的学习教程(四)之 SpringBoot 集成 Shiro 原理

news2024/9/23 23:25:44

目录

  • 1、第一阶段:启动服务,构建类的功能
  • 2、第二阶段:正式请求

1、第一阶段:启动服务,构建类的功能

查看 Shiro 配置类 ShiroConfiguration

@Configuration
public class ShiroConfiguration {
    // 创建 shiroFilter,负责拦截所有请求
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置系统受限资源
        //配置系统公共资源
        Map<String,String> map = new HashMap<>();
        // authc 请求这个资源需要认证和授权
        map.put("/login", "anon");
        map.put("/register", "anon");
        map.put("/user/register", "anon");
        map.put("/user/login", "anon");
        map.put("/index", "authc");
        //默认认证界面路径
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }
}

配置了 ShiroFilterFactoryBean

查看 ShiroFilterFactoryBean实现了 FactoryBean 接口

public class ShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor {

	private SecurityManager securityManager;
	// 用于自定义的 filter
    private Map<String, Filter> filters = new LinkedHashMap();
    // 用于自定义的过滤器链
    private Map<String, String> filterChainDefinitionMap = new LinkedHashMap();
    // 设置全局的 url
    private String loginUrl;
    private String successUrl;
    private String unauthorizedUrl;
    // 生成的实例
    private AbstractShiroFilter instance;
    
	// ...
	
	public Object getObject() throws Exception {
        if (this.instance == null) {
            this.instance = this.createInstance();
        }
        return this.instance;
    }
	
	protected AbstractShiroFilter createInstance() throws Exception {
        log.debug("Creating Shiro Filter instance.");
        FilterChainManager manager = this.createFilterChainManager();
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);
        return new ShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
    }
    
    // ...
}
  • Map<String, Filter> filterskey 是过滤器名称,value 是 Filter
  • Map<String, String> filterChainDefinitionMapkey 是 uri,value 是过滤器名称

Spring 容器会自动检测到 FactoryBean 接口,并调用其 getObject() 方法获取实际的 bean 对象,所以,最终会调用 createInstance() 方法。

createInstance() 方法:创建 FilterChainManager 对象、PathMatchingFilterChainResolverPathMatchingFilterChainResolver 设置了 FilterChainManager)对象,再创建了内部类 SpringShiroFilter 对象

  1. this.createFilterChainManager():创建 FilterChainManager
    • 创建 DefaultFilterChainManager 实例,并将默认过滤器、自定义过滤器存放到属性 Map<String, Filter> filters
    • 并给所有的过滤器设置 urlloginUrlsuccessUrlunauthorizedUrl
    • 构造过滤器链,并存放到属性 Map<String, NamedFilterList> filterChains,其中,key 为 uri,value 为 NamedFilterList (extends List<Filter>);并将 uri 存放在 PathMatchingFilter 类的 Map<String, Object> appliedPaths 属性

createFilterChainManager() 方法:

在这里插入图片描述

①:new DefaultFilterChainManager():管理 过滤器 filters(包括默认过滤器 + 自定义过滤器)、过滤器链

在这里插入图片描述
在构造器中,将默认的过滤器添加到 filters 属性中

默认过滤器 DefaultFilter:枚举类

public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    authcBearer(BearerHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);
}

②:applyGlobalPropertiesIfNecessary(filter):设置 loginUrlsuccessUrlunauthorizedUrl

在这里插入图片描述

applyLoginUrlIfNecessary() 方法为例:

在这里插入图片描述
在这里插入图片描述

如果 ShiroFilterFactoryBean#loginUrl 有值且 AccessControlFilter#loginUrl 的值为默认值(/login.jsp),那么就会给 AccessControlFilter#loginUrl 设置值

③:处理自定义的过滤器 filter:将自定义过滤器添加到 DefaultFilterChainManager

在这里插入图片描述

④:getFilterChainDefinitionMap() & createChain():构造过滤器链

createChain() 方法:

在这里插入图片描述

注意下面这行代码:

String[] filterTokens = this.splitChainDefinition(chainDefinition);

将一个字符串可以转化为字符串数组,就可猜测是不是可以配置多个过滤器 map.put("/login", "anon, authc");

对此数组进行 for 循环:

String[] nameConfigPair = this.toNameConfigPair(token);
this.addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);

又将一个字符串 token 转化为了一个 字符串数组,且通过 "["toNameConfigPair 内部实现)将数组分为了两部分

所以,最终可以配置成:

map.put("/login", "authc, roles[admin,user], perms[file:edit]");

addToChain() 方法:生成带有 name(过滤 uri)的过滤器链 NamedFilterList,并将过滤器添加其中(过滤 uri 和过滤器是一对多关系)

在这里插入图片描述

1、applyChainConfig() 方法:存放所有的过滤 uri

在这里插入图片描述

1-1、PathMatchingFilter#processPathConfig() 方法:

  • 属性
    • PatternMatcher pathMatcher:用于请求 uri 和已配置的 uri 进行配置
    • Map<String, Object> appliedPaths: 存放所有的过滤 uri

在这里插入图片描述

2、ensureChain(chainName) 方法:通过 uri 获取过滤器链,如果没有,则创建 SimpleNamedFilterList,并将此过滤器链放入 filterChains 属性中,返回;如果通过 uri 获取到过滤器链,则直接返回

在这里插入图片描述

2-1、SimpleNamedFilterList:其实就是一个有名字 name 的 List<Filter>

  • name:uri
  • List<Filter>:配置的过滤器

一个 uri 可以对应多个过滤器,所以,Filter 是一个 List 集合

在这里插入图片描述

  1. new PathMatchingFilterChainResolver():创建 PathMatchingFilterChainResolver,负责路径和过滤器链的解析、匹配,根据 url 找到过滤器链

2、第二阶段:正式请求

任何请求都会先经过 Shiro 先过滤,直到成功才会执行 web 本身的过滤器

一个请求过来时,先到达 AbstractShiroFilter#executeChain()方法,去根据 request 解析出来的 url 找到对应的过滤链,然后执行过滤器链。

1、executeChain() 方法如下:

在这里插入图片描述

1-1、getExecutionChain() 方法:这里的 resolver 就是 PathMatchingFilterChainResolver,根据 uri 获取过滤器链 ProxiedFilterChain

在这里插入图片描述

1-2、getChain() 方法:从属性 filterChains 循环匹配请求 uri,若匹配成功,则调用 filterChainManager.proxy();否则,返回 null

在这里插入图片描述

1-2-1、pathMatches() 方法:

在这里插入图片描述

1-2-1-1、AntPathMatcher#matches():使用 AntPathMatcher 进行匹配

在这里插入图片描述

doMatch():匹配 uri 和 requestUri,考虑到通配符 **

在这里插入图片描述

2、chain.doFilter(request, response);:执行过滤器链

在这里插入图片描述
在这里插入图片描述

过滤器类结构图:

在这里插入图片描述

最终调用 AdviceFilter#doFilterInternal() 方法:preHandle() 方法决定过滤器链是否执行

在这里插入图片描述

通过属性 appliedPaths 循环判断是否与当前请求的 uri 相匹配,如果通过,直接返回 true,否则,进入 onPreHandle() 方法判断:

在这里插入图片描述

onPreHandle() 方法供子类去重写:

在这里插入图片描述

AnonymousFilter:匿名访问。

在这里插入图片描述
任何对象访问都一直返回 true,表明任何用 AnonymousFilter 过滤的请求都不需要验证。因为它一直返回 true

AccessControlFilter:需要身份验证的过滤器

在这里插入图片描述

isAccessAllowed()onAccessDenied() 方法决定

  • isAccessAllowed():决定了当前请求的subject是否允许访问
  • onAccessDenied():在被拒绝访问时处理。AccessControlFilter 类有很多子类重载了该方法。以 FormAuthenticationFilter 类的onAccessDenied() 方法为例

在这里插入图片描述
如果是登陆请求,则执行登陆操作;否则,保存请求链接跳转到登陆请求界面

executeLogin() 方法:创建 token,调用 Subject#login() 方法

在这里插入图片描述
总结流程:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2126733.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法里面的离散化

一、离散化&#xff08;discretization&#xff09;在算法和数据结构中指的是将连续的输入数据映射到离散的值或者范围&#xff0c;从而使得处理和计算变得更高效。通常用于处理大范围或者无限可能的输入&#xff0c;以便将其转化为有限的、可以有效处理的范围。 离散化的定义…

opencv之傅里叶变换

文章目录 前言理论基础Numpy实现傅里叶变换实现傅里叶变换实现逆傅里叶变换 高通滤波示例OpenCV实现傅里叶变换实现傅里叶变换实现逆傅里叶变换 低通滤波示例 前言 图像处理一般分为空间域处理和频率域处理。 空间域处理是直接对图像内的像素进行处理。空间域处理主要划分为灰…

Mysql基础练习题 1757.可回收且低脂的产品(力扣)

编写解决方案找出既是低脂又是可回收的产品编号。 题目链接&#xff1a; https://leetcode.cn/problems/recyclable-and-low-fat-products/description/ 建表插入数据&#xff1a; Create table If Not Exists Products (product_id int, low_fats ENUM(Y, N), recyclable …

Kernel 内核 BUG_ON()和WARN_ON()

WARN_ON() DEBUG_ON() 不是一个标准的 Linux 内核宏&#xff0c;它可能是特定内核版本或者特定内核配置中的一个宏&#xff0c;或者在某些内核代码中自定义的宏。一般来说&#xff0c;如果存在 DEBUG_ON()&#xff0c;它可能被用作一个调试开关&#xff0c;用于在调试版本中启…

2024.9.11

时钟 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent> #include <QTimer> #include <QPainter> #include <QPen> #include <QBrush> #include <QTime> #include <QDebug> QT_BEGIN_NA…

国内如何优雅的用Google?无需安装任何工具!

前言 Google可以说时每个程序猿的标配&#xff0c;但由于网络问题&#xff0c;在访问Google的时候或多或少都会遇到一系列的问题&#xff0c;接下来介绍一个非常“炸裂”的Google打开方式。 LiteIcoding 在此之前&#xff0c;你需要访问这个地址 https://lite.icoding.ink 这…

【Qt】QSS的设置方式

QSS的设置方式 QWidget 中包含了 setStyleSheet ⽅法, 可以直接设置样式. 上述代码我们已经演⽰了上述设置⽅式 还可以通过 QApplication 的 setStyleSheet ⽅法设置整个程序的全局样式. 设置全局样式&#xff0c;可以将界面上所有的样式都集中到一起来组织。 全局样式优点:…

56 - II. 数组中数字出现的次数 II

comments: true difficulty: 中等 edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9856%20-%20II.%20%E6%95%B0%E7%BB%84%E4%B8%AD%E6%95%B0%E5%AD%97%E5%87%BA%E7%8E%B0%E7%9A%84%E6%AC%A1%E6%95%B0%20II/README.md 面试题 56 - II. 数…

大屏可视化常用图标效果表达

1-echarts-雷达图 2-echarts-仪表盘 3-echarts-水球图&#xff08;利用插件&#xff0c;echarts-liquidfill&#xff09; 4-element UI tree 添加连接线&#xff0c;修改样式或使用插件&#xff08;element-tree-line&#xff09; 5-echarts-漏斗图 6-echarts-饼状图嵌套 optio…

力扣刷题之2181.合并零之间的节点

题干描述 给你一个链表的头节点 head &#xff0c;该链表包含由 0 分隔开的一连串整数。链表的 开端 和 末尾 的节点都满足 Node.val 0 。 对于每两个相邻的 0 &#xff0c;请你将它们之间的所有节点合并成一个节点&#xff0c;其值是所有已合并节点的值之和。然后将所有 0 …

为什么 1T 的硬盘容量只有 931G?真相在这里!

硬盘容量疑问 以一个容量为 1T 的硬盘为例&#xff0c;在 Windows 系统下&#xff0c;容量显示只有 931G&#xff0c;不应该是 1024GB 吗&#xff1f;这到底是为什么呢&#xff1f;是商家在欺骗消费者吗&#xff1f; 按照之前内存大小的计算逻辑&#xff08;1MB 1024KB&…

AI电商,如何提高设计效率?

第一步&#xff1a;找参考 第二步&#xff1a;提取关键词 我用的文心一言 第三步&#xff1a;选择AI绘画工具&#xff08;千鹿 设计助手&#xff09; 千鹿设计助手——FLux文生图&#xff0c;你也可以选择你手上的AI绘画工具 这个新用户注册会赠送1000积分 第四步生图

[笔记] 电机工作制以及软硬特性的本质推导

原始资料来源&#xff1a;某电机厂商 1.电机非常规操作术语和许可次数 1.1 电机操作术语 点动&#xff1a;通电后立即关停&#xff0c;最终速度不到额定转速的1/4电制动&#xff1a;制动到额定转速的1/3逆转&#xff1a;也就是打反车&#xff0c;不等停车&#xff0c;立即翻…

Java、python、php三个版本 抗震救灾物资管理系统 抗洪救灾物资分配系统 救援物资申请平台(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

在 Web 中判断页面是不是刷新

在 Web 开发中&#xff0c;我们经常需要区分用户是否通过刷新操作重新加载了页面。这一操作可能是由用户手动刷新&#xff08;如按下 F5 键或点击浏览器刷新按钮&#xff09;或通过浏览器自动重新加载。判断页面是否刷新有助于开发者优化用户体验&#xff0c;例如在使用 vue 的…

超详细,手把手带你源码启动 Thingsboard-Gateway + MQTT 接入设备

超详细&#xff0c;手把手带你源码启动 Thingsboard-Gateway MQTT 接入设备 前置条件 thingsboard&#xff0c;我这里选择的是本地源码启动postgresql&#xff0c;这里采用的是个人服务器部署的公共服务EMQX&#xff0c;这里同样采用服务器部署的公共服务MQTTX 客户端Mysql【…

Fiddle的使用------一个非常好用且正规的抓包工具

Fiddle的下载安装&#xff08;看完再去下载安装&#xff09; https://www.telerik.com/download/fiddler 1.点击连接&#xff0c;在表格填上数据&#xff0c;点击下载&#xff0c;下载结束了就安装&#xff0c;一路next就可以了。 2.修改一下设置 以上跟我一样设置&#xff…

Unity 是否能和黑神话悟空一样,接入Nivida的DLSS,用NSight Graphics实际测试

NSight作为Nivida 显卡的调试工具&#xff0c;因为国内都是手游开发盛行的年代&#xff0c;远没有RenderDoc或者高通的QuatXXX 出名 选择NSight的原因很简单&#xff1a; Nividia 财大气粗&#xff0c;倒不是主因&#xff0c; 因为其CEO爱出名&#xff0c;所以手下的人只…

视觉SLAM ch5——相机与图像

一、单目模型 前言&#xff1a;本大标题下1~4部分讲述的都是单目针孔相机 SLAM的数学本质可以抽象为运动方程&#xff08;x&#xff09;和观测方程&#xff08;z&#xff09;&#xff08;书上的第二部分&#xff09; 教材第二章截图 书中P24页截图 其中的未知量为xk&#xff…

828华为云征文|几分钟,即可在华为云Flexus X服务器部署安全稳定的——水果生鲜商城配送小程序

最近由于公司需要开发一个水果生鲜同城配送的小程序&#xff0c;源码代码已经有了&#xff0c;相对于应的功能也开发的七七八八了&#xff0c;随着生鲜商城小程序的相对于应的功能开发逐渐接近尾声。 然而&#xff0c;在这个关键时刻&#xff0c;一个至关重要的决定摆在了团队面…