解决 MDCFilter 引起的 Shiro UnavailableSecurityManagerException 异常:将过滤器交给 Shiro 管理

news2024/9/21 8:01:48

若将自定义的 MDCFilter 注册到 FilterRegistrationBean 中,而又在 MDCFilter 中使用了和 Shiro 相关的操作(如获取当前登录用户),此时会因为 MDCFilter 先于 SecurityManager 实例化导致出现 UnavailableSecurityManagerException 的异常,我们只需将 MDCFilter 注册到 Shiro 的过滤器链中即可解决这个问题。


文章目录

  • 1.环境描述
  • 2.问题描述
  • 3.问题分析
  • 4.问题解决


1.环境描述

  • Springboot 3.1.5
  • Shiro 1.12.0

2.问题描述

为了加入 trace 的能力,自定义了一个 MDCFilter,继承Filter,并交给 Spring 容器管理:

@Component
public class MDCFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        MDC.put(MdcConstant.TRACE_ID, IdUtil.fastUUID());
        MDC.put(MdcConstant.IP, IpUtils.getIpAddr(httpServletRequest));
        MDC.put(MdcConstant.USER, TokenUtils.isLogin() ? TokenUtils.getLoginUserId() : "anonymous");

        try {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        } finally {
            MDC.clear();
        }
    }

}

同时在 FilterRegistrationBean 中注册该过滤器:

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<MyFilter> loggingFilter() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();

        registrationBean.setFilter(new MDCFilter());
        registrationBean.addUrlPatterns("/api/*");

        return registrationBean;
    }
}

本地启动正常,部署服务器后,发送请求就会出现如下异常 UnavailableSecurityManagerException(关键类路径脱敏处理):

2024-07-24 18:25:58.336 ERROR 1757379 --- [9c77170a-55f6-4256-b5be-590c5952443d] [                   ] [ 113.54.159.100] [nio-8188-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet]    175    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application configuration.
	at org.apache.shiro.SecurityUtils.getSecurityManager(SecurityUtils.java:123)
	at org.apache.shiro.subject.Subject$Builder.<init>(Subject.java:626)
	at org.apache.shiro.SecurityUtils.getSubject(SecurityUtils.java:56)
	at *.TokenUtils.getLoginUser(TokenUtils.java:28)
	at *.isLogin(TokenUtils.java:37)
	at *.MDCFilter.doFilter(MDCFilter.java:38)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:833)

3.问题分析

简单测试后可以发现 SecurityManager 是在 Spring 容器中的,但是断点打到 SecurityManager 实例化的地方可以发现此时 MDCFilter 已经在 Shiro 的 filter 之前注册了,那么在请求到来的时候, MDCFilter 中调用 TokenUtils.getLoginUser,此时还未执行 shiro 的 filter,就会导致 UnavailableSecurityManagerException 的异常。

为什么 MDCFilter 会先于 SecurityManager 注册?
因为 Spring 优先加载容器中的 Filter, Shiro 中的 Filter由 Shiro 负责完成加载过程。

为什么会出现本地部署和服务器部署加载顺序不一致的问题?
这一点没有仔细去调试,猜测由于不同操作系统某些底层默认配置不一致,日后如果再遇到类似的问题可以深入研究下。

4.问题解决

解决问题就很简单了,我们把 MDCFilter 同样交给 Shiro 管理即可,注册在其过滤器链中:


ATFWUS 2024-07-25

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

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

相关文章

C语言 ——— 函数指针数组的讲解及其用法

目录 前言 函数指针数组的定义 函数指针数组的使用 前言 数组是存放一组相同类型数据的存储空间 关于指针数组的知识请见&#xff1a;C语言 ——— 指针数组 & 指针数组模拟二维整型数组-CSDN博客 那么要将多个函数的地址存储到数组中&#xff0c;这个数组该如何定义…

太原高校大学智能制造实验室数字孪生可视化系统平台建设项目验收

随着科技的不断进步&#xff0c;智能制造已经成为推动制造业转型升级的重要力量。太原高校大学智能制造实验室紧跟时代步伐&#xff0c;积极推进数字孪生可视化系统平台的建设&#xff0c;并于近日圆满完成了项目的验收工作。这一里程碑式的成果&#xff0c;不仅标志着实验室在…

Angular由一个bug说起之八:实践中遇到的一个数据颗粒度的问题

互联网产品离不开数据处理&#xff0c;数据处理有一些基本的原则包括&#xff1a;准确性、‌完整性、‌一致性、‌保密性、‌及时性。‌ 准确性&#xff1a;是数据处理的首要目标&#xff0c;‌确保数据的真实性和可靠性。‌准确的数据是进行分析和决策的基础&#xff0c;‌因此…

Three.js投射光线实现三维物体交互

<template><div id"webgl"></div> </template><script setup> import * as THREE from three //导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls // 导入 dat.gui import { GUI } from thre…

谷粒商城实战笔记-43-前端基础-Vue-使用Vue脚手架进行模块化开发

文章目录 一&#xff0c;Vue的模块化开发1&#xff0c;目录结构2&#xff0c;单文件组件 (SFC)3&#xff0c;模块化路由4&#xff0c;Vuex 模块5&#xff0c;动态组件和异步组件6&#xff0c;抽象和复用7&#xff0c;构建和打包8&#xff0c;测试9&#xff0c;文档和注释10&…

基于Neo4j将知识图谱用于检索增强生成:Knowledge Graphs for RAG

Knowledge Graphs for RAG 本文是学习https://www.deeplearning.ai/short-courses/knowledge-graphs-rag/这门课的学习笔记。 What you’ll learn in this course Knowledge graphs are used in development to structure complex data relationships, drive intelligent sea…

Node.js知识点总结

Node.js知识点总结 Node.js其本质和浏览器一样是一个JavaScript运行环境。浏览器的运行环境为V8引擎浏览器内置API&#xff08;BOM、DOM、Canvas);而node.js的运行环境是V8引擎node提供的API(fs、path、http)。它使JavaScript可以编写后端。 基本知识 fs文件系统模块 它提供一…

深度学习复盘与论文复现E

文章目录 一、项目复现的问题及其解决方案1、 Cannot find DGL C graphbolt library2、 “is“ with a literal. Did you mean ““?”3、运行SEG、SPG查看GATNet的网络结构4、关于LI-FPN项目找不到数据粒度不匹配问题5、关于LI-FPN项目num_samples为空6、解决路径问题7、 !ss…

Nginx 怎样处理请求的缓存数据清理策略?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; 文章目录 Nginx 怎样处理请求的缓存数据清理策略&#xff1f;一、理解 Nginx 缓存的重要性二、Nginx 缓存数据的类型&#xff08;一&#xff09;静态文件缓存&#xff08;…

PHP简单商城单商户小程序系统源码

&#x1f6cd;️轻松开店&#xff0c;触手可及&#xff01;「简单商城小程序」让电商梦想照进现实&#x1f31f; &#x1f389;开店新风尚&#xff0c;「简单商城小程序」引领潮流&#xff01; 还在为繁琐的电商开店流程烦恼吗&#xff1f;想要快速搭建自己的线上商城&#x…

Linux嵌入式学习——数据结构——线性表的链式结构

线性表的链式存储 解决顺序存储的缺点&#xff0c;插入和删除&#xff0c;动态存储问题。 特点&#xff1a; 线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素&#xff0c;存储单元可以是连续的&#xff0c;也可以不连续。可以被存储在任意内存未被占…

vue3如何实现分面漏斗图

如下图&#xff1a; 这里我选择采用Vue3g2plot进行实现。 参考网址&#xff1a;https://g2plot.antv.antgroup.com/zh/examples/more-plots/funnel/#facet-transpose 核心代码如下&#xff1a; const data [{ stage: 简历筛选, number: 253, company: A公司 },{ stage: 初…

东京裸机云多IP服务器全面分析

东京裸机云多IP服务器是一种提供多IP地址分配和高性能网络服务的云计算解决方案&#xff0c;广泛应用于需要多IP管理和高稳定性的网络应用。下面将从几个方面具体介绍东京裸机云多IP服务器&#xff0c;rak部落为您整理发布东京裸机云多IP服务器的全面分析。 在数字化时代&#…

Docker 部署常用中间件(redis,rabbitMQ,mysql8,es,kibana,nginx等)亲测成功~~~

Docker 部署常用中间件 在日常开发中必要的环境&#xff0c;大多数都是单点后续持续更新集群模式~~~ docker 安装reids docker pull redis:7.2.5 编辑redis.conf # 绑定地址&#xff0c;默认只允许本机访问 # bind 192.168.1.100 10.0.0.1 # bind 127.0.0.1 ::1 bind 0.0…

学员心得 | 做好这几点,轻松通关云计算HCIE3.0!

烈日当空&#xff0c;骄阳似火&#xff0c;在这炎炎夏日迎来了自己今年一份满意的答卷--华为HCIE云计算“通过”的e妹儿&#xff08;嘿嘿&#xff01;证书也快了&#xff09;。此时此刻&#xff0c;想把自己“辛勤劳作”备考IE的一些经历和建议留给后来的同路人。 “世界上最可…

MySQL练手 --- 619. 只出现一次的最大数字

题目链接&#xff1a;619. 只出现一次的最大数字 思路 这是一个简单题&#xff0c;只出现一次的最大数字&#xff0c;顾名思义&#xff0c;分两个阶段&#xff0c;第一个阶段筛选出只出现一次的数字&#xff0c;第二阶段在生成的新表中筛选出最大值即可。 解题过程 生成一张…

iOS object-C 解答算法:找到所有数组中消失的数字(leetCode-448)

找到所有数组中消失的数字(leetCode-448) 题目如下图:(也可以到leetCode上看完整题目,题号448) 光看题看可能有点难以理解,我们结合示例1来理解一下这道题. 有8个整数的数组 nums [4,3,2,7,8,2,3,1], 求在闭区间[1,8]范围内(即1,2,3,4,5,6,7,8)的数字,哪几个没有出现在数组 …

华为OD机试 - 二叉树计算(Java JS Python C C++)

题目描述 给出一个二叉树如下图所示: 请由该二叉树生成一个新的二叉树,它满足其树中的每个节点将包含原始树中的左子树和右子树的和。 左子树表示该节点左侧叶子节点为根节点的一颗新树;右子树表示该节点右侧叶子节点为根节点的一颗新树。 输入描述 2行整数,第1行表示二叉…

MySQL数据库-备份恢复

一、MySQL日志管理 1.为什么需要日志 用于排错用来做数据分析了解程序的运行情况&#xff0c;了解MySQL的性能 2.日志作用 在数据库保存数据时&#xff0c;有时候不可避免会出现数据丢失或者被破坏&#xff0c;这样情况下&#xff0c;就必须保证数据的安全性和完整性&#…

Spring AI (五) Message 消息

5.Message 消息 在Spring AI提供的接口中&#xff0c;每条信息的角色总共分为三类&#xff1a; SystemMessage&#xff1a;系统限制信息&#xff0c;这种信息在对话中的权重很大&#xff0c;AI会优先依据SystemMessage里的内容进行回复&#xff1b; UserMessage&#xff1a;用…