Spring Security与Spring MVC集成报错:缺失mvcHandlerMappingIntrospector Bean
mvcHandlerMappingIntrospector Bean 我是Spring新手,想实现用户登录后才能访问特定端点。跟着《Spring MVC Beginner's Guide》里的代码操作,但跑不起来,报错如下(仅贴出栈追踪首尾):
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChains': Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#0' while setting bean property 'sourceList' with key [0] ... Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'mvcHandlerMappingIntrospector' available: A Bean named mvcHandlerMappingIntrospector of type org.springframework.web.servlet.handler.HandlerMappingIntrospector is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.
我的配置文件如下:
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.packt</groupId> <artifactId>webstore</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.2.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>jakarta.servlet.jsp.jstl</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>jakarta.servlet.jsp.jstl</groupId> <artifactId>jakarta.servlet.jsp.jstl-api</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>6.4.1</version> <exclusions> <exclusion> <artifactId>spring-asm</artifactId> <groupId>org.springframework</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>6.4.1</version> </dependency> </dependencies> <build> <finalName>webstore</finalName> </build> </project>
web.xml配置
<servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/ WEB-INF/spring/webcontext/DispatcherServlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring/webcontext/security-context.xml </param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class> org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
security-context.xml配置
<security:http auto-config="true"> <security:intercept-url pattern="/products/add" access="ROLE_ADMIN"/> <security:form-login login-page="/login" default-target-url="/products/add" authentication-failure-url="/loginfailed" always-use-default-target="true" /> <security:logout logout-success-url="/logout"/> </security:http> <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="Admin" password="{noop}Admin123" authorities="ROLE_ADMIN"/> </security:user-service> </security:authentication-provider> </security:authentication-manager>
我试过修改web.xml:移除springSecurityFilterChain后应用能构建但登录功能失效;也试过移除<context-param>并将security-context.xml路径配置到servlet的contextConfigLocation中,但问题仍未解决。
问题根源
报错核心原因是:Spring Security和Spring MVC的配置分别加载在父子ApplicationContext中(Security在父上下文,MVC在子上下文),父上下文无法访问子上下文的Bean,而Spring Security需要用到MVC的mvcHandlerMappingIntrospector Bean,导致找不到依赖。
修复步骤
合并上下文配置
将Spring Security的配置并入DispatcherServlet的上下文,同时移除ContextLoaderListener相关配置,确保两者共享同一个ApplicationContext:<servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!-- 注意去掉路径中的空格,同时添加security配置文件 --> <param-value>/WEB-INF/spring/webcontext/DispatcherServlet-context.xml /WEB-INF/spring/webcontext/security-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 移除ContextLoaderListener相关配置 --> <!-- <context-param>...</context-param> --> <!-- <listener>...</listener> --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>统一Spring版本
当前Spring MVC(6.2.0)和Spring Security(6.4.1)版本不一致,可能存在兼容隐患,将Spring MVC版本改为6.4.1:<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.4.1</version> <scope>compile</scope> </dependency>开启MVC注解驱动
在DispatcherServlet-context.xml中添加MVC注解驱动配置,让Spring自动创建mvcHandlerMappingIntrospectorBean:<!-- 先引入mvc命名空间 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 开启MVC注解驱动 --> <mvc:annotation-driven /> <!-- 其他MVC配置 --> </beans>
验证修复
完成上述修改后,重新构建并启动应用:
- 访问
/products/add会自动跳转到登录页面 - 使用账号
Admin、密码Admin123登录后,即可正常访问该端点
内容的提问来源于stack exchange,提问作者Tyraneiro

