【Shiro】Shiro 的学习教程(四)之 SpringBoot 集成 Shiro 原理
目录
- 1、第一阶段:启动服务,构建类的功能
- 2、第二阶段:正式请求
1、第一阶段:启动服务,构建类的功能
查看 Shiro 配置类 ShiroConfiguration:
@Configuration
public class ShiroConfiguration {// 创建 shiroFilter,负责拦截所有请求@Beanpublic 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;// 用于自定义的 filterprivate Map<String, Filter> filters = new LinkedHashMap();// 用于自定义的过滤器链private Map<String, String> filterChainDefinitionMap = new LinkedHashMap();// 设置全局的 urlprivate 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> filters:key 是过滤器名称,value 是FilterMap<String, String> filterChainDefinitionMap:key 是 uri,value 是过滤器名称
Spring 容器会自动检测到 FactoryBean 接口,并调用其 getObject() 方法获取实际的 bean 对象,所以,最终会调用 createInstance() 方法。
createInstance()方法:创建FilterChainManager对象、PathMatchingFilterChainResolver(PathMatchingFilterChainResolver设置了FilterChainManager)对象,再创建了内部类SpringShiroFilter对象
this.createFilterChainManager():创建FilterChainManager。- 创建
DefaultFilterChainManager实例,并将默认过滤器、自定义过滤器存放到属性 Map<String, Filter> filters ; - 并给所有的过滤器设置
url:loginUrl、successUrl、unauthorizedUrl - 构造过滤器链,并存放到属性 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):设置 loginUrl、successUrl、unauthorizedUrl

以 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 集合

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() 方法

总结流程:

相关文章:
【Shiro】Shiro 的学习教程(四)之 SpringBoot 集成 Shiro 原理
目录 1、第一阶段:启动服务,构建类的功能2、第二阶段:正式请求 1、第一阶段:启动服务,构建类的功能 查看 Shiro 配置类 ShiroConfiguration: Configuration public class ShiroConfiguration {// 创建 sh…...
多线程篇(阻塞队列- PriorityBlockingQueue)(持续更新迭代)
目录 一、简介 二、类图 三、源码解析 1. 字段讲解 2. 构造方法 3. 入队方法 put 浮调整比较器方法的实现 入队图解 4. 出队方法 take dequeue 下沉调整比较器方法的实现 出队图解 四、总结 一、简介 PriorityBlockingQueue队列是 JDK1.5 的时候出来的一个阻塞…...
strstr函数的使用和模拟实现
目录 1.头文件 2.strstr函数的使用 3.strstr函数模拟实现 小心!VS2022不可直接接触,否则!没这个必要,方源面色淡然一把抓住!顷刻炼化! 1.头文件 strstr函数的使用需要头文件 #include<string.h>…...
使用Selenium与WebDriver实现跨浏览器自动化数据抓取
背景/引言 在数据驱动的时代,网络爬虫成为了收集和分析海量数据的关键工具。为了应对不同浏览器环境下的兼容性问题,Selenium与WebDriver成为了开发者实现跨浏览器自动化数据抓取的首选工具。本文将深入探讨如何利用Selenium和WebDriver实现跨浏览器的数…...
信创实践(3):基于x2openEuler将CentOS升级成openEuler,享受其带来的创新和安全特性
引言: 在当前的 IT 行业中,创新和安全性是两大关键趋势。随着 CentOS 停止维护,许多用户正在寻找替代方案,以保持其系统的更新和安全。openEuler 作为一个强大的开源操作系统,成为了理想的迁移目标。本教程将指导您如…...
LEAN 类型理论之注解(Annotations of LEAN Type Theory)-- 相等类型(Equality Type)
《何谓相等 (Equality),在类型理论(Type Theory)语境下》 与 《转化(conversion and reduction)后的相等(Equality)》,两文中,已对相等(Equality)的概念进行了描述&#…...
Idea 创建 Maven项目的时候卡死
文章目录 一、Archetype 和 Catalog1.1 Archetype(原型)1.2 Catalog(目录) 二、可能遇到的问题2.1 问题描述2.2 原因分析2.3 解决方案 参考资料 一、Archetype 和 Catalog 1.1 Archetype(原型) Archetype…...
C++入门(02)简单了解C++应用程序的开发部署
文章目录 1. 开发C应用程序2. 简单示例计算器程序3. 需求分析4. 设计5. 编码6. 编译7. 调试8. 测试9. 部署10. 部署示例10.1 使用Visual Studio Installer Projects创建安装程序10.2 安装VisualStudio Installer Projects扩展10.3 在calculator解决方案中创建安装项目10.3.1 添…...
有了室内外一体化人行导航,你还怕迷路吗?
在快节奏的现代生活中,无论是穿梭于繁华的都市丛林,还是漫步于错综复杂的购物中心,迷路似乎成了不少人的“小确丧”。然而,随着科技的飞速发展,一项革命性的创新——室内外一体化人行导航系统,正悄然改变着…...
Python虚拟环境包迁移
1. 激活源虚拟环境 首先,激活你想要导出包的源虚拟环境。在命令行中输入: Windows: path\to\your\source_env\Scripts\activatemacOS/Linux: source path/to/your/source_env/bin/activate 2. 导出已安装包的列表 使用以下命令生成一个requirements…...
利用分布式锁在ASP.NET Core中实现防抖
前言 在 Web 应用开发过程中,防抖(Debounce) 是确保同一操作在短时间内不会被重复触发的一种有效手段。常见的场景包括防止用户在短时间内重复提交表单,或者避免多次点击按钮导致后台服务执行多次相同的操作。无论在单机环境中&a…...
Django+Vue3前后端分离学习(二)(重写User类)
一、重写User类: 1、首先导入User类: from django.contrib.auth.models import User 2、然后点在User上,按住ctrl 点进去,发现 User类继承AbstractUser Ctrl点进去AbstractUser,然后将此方法全部复制到自己APP的mo…...
兔英语语法体系——观后笔记
目录 一、视频链接 二、视频前言 三、简单句(Simple Sentences) 1. 可独立完成的动作 2. 有1个动作的承受者 3. 有两个动作承受者 4. 只有一个动作承受者(但需补充) 5. 非 “动作” 6. 总结 四、五大基本句型 五、句子成分 6. 定语 7. 状语 8. 同位语 9. 总结 …...
哈希表如何避免冲突
系列文章: 1. 先导片--Map&Set之二叉搜索树 2. Map&Set之相关概念 3. 哈希表如何避免冲突 目录 1.概念 2. 冲突-概念 3. 冲突-避免 3.1 冲突-避免-哈希函数设计 3.2 冲突-避免-负载因子调节 4. 冲突-解决 4.1 冲突-解决-闭散列 4.1.1 线性探…...
内核模块驱动开发
内核模块开始学习前,一定是最先接触到内核模块三要素(面试),驱动入口、驱动出口和协议的遵循。 1.内核模块三要素(面试)//修饰模块化驱动的入口函数module_init(demo_init);//修饰模块化驱动的出口函数module_eixt(demo_exit);//遵循GPL开源协议MODULE_…...
Linux 下 alsa 库录音并保存为 WAV 格式
麦克风列表: [jnjn build]$ arecord -l **** List of CAPTURE Hardware Devices **** card 0: AudioPCI [Ensoniq AudioPCI], device 0: ES1371/1 [ES1371 DAC2/ADC]Subdevices: 1/1Subdevice #0: subdevice #0 card 1: Camera [2K USB Camera], device 0: USB Aud…...
使用stripe进行在线支付、退款、订阅、取消订阅功能(uniapp+h5)
stripe官网:Stripe 登录 | 登录 Stripe 管理平台 然后在首页当中打开测试模式,使用测试的公钥跟私钥进行开发 测试卡号 4242 4242 4242 4242 1234 567 在线支付 stripe的在线支付有两种,第一种就是无代码,第二中就是使用api进行自定义,一般来说推荐第二种进行开发 无…...
深度学习中常见的损失函数
关注B站可以观看更多实战教学视频:hallo128的个人空间 深度学习中常见的损失函数 损失函数的作用 损失函数是衡量神经网络输出与真实标签之间差距的指标。在训练过程中,神经网络的目标是最小化损失函数的值。常见的损失函数包括均方误差(MS…...
认识Linux及Linux的环境搭建
目录 1、什么是Linux2、Linux环境搭建2.1 下载安装 Xshell2.2 下载安装 VMware Workstation Pro2.3 选择适合自己系统 1、什么是Linux Linux,一般指GNU/Linux(单独的Linux内核并不可直接使用,一般搭配GNU套件,故得此称呼ÿ…...
Java之线程篇三
目录 线程状态 观察线程的所有状态 线程状态及其描述 线程状态转换 代码示例1 代码示例2 线程安全 概念 线程不安全的代码示例 线程不安全的原因 线程安全的代码示例-加锁 synchronized关键字 synchronized的特性 小结 形成死锁的四个必要条件 …...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 原创笔记:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 上一篇:《数据结构第4章 数组和广义表》…...
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...
