Spring Security在Tomcat 10中无法显示登录页问题求助
问题描述
我开发了一个用于验证Spring Security实现的小型Web应用,该应用在Tomcat 9服务器上运行正常,可显示登录页;但部署到Tomcat 10后,登录页无法显示。以下是应用的组件信息:
web.xml配置
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> </web-app>
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.sharex30</groupId> <artifactId>SSA</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>MavenBootstrap Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- PARAMETRAGE SERVLET --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>javax.servlet.jsp.jstl-api</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2</version> </dependency> <!-- SECURITY --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.1.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.1.3.RELEASE</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> </dependencies> <build> <finalName>MavenBootstrap</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
两个Java类
SecurityConfig.java
package com.sharex30.security; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.*; @EnableWebSecurity public class SecurityConfig { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user").password("password").roles("USER"); } }
SecurityWebApplicationInitializer.java
package com.sharex30.security; import org.springframework.security.web.context.*; public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { public SecurityWebApplicationInitializer() { super(SecurityConfig.class); } }
网页文件
<!DOCTYPE html> <html> <head> <link href="https://fonts.googleapis.com/css?family=Arial" rel="stylesheet"> <link type="text/css" href="resources/styles/index.css" rel="stylesheet"> </head> <body> <div> <div class="d1">MavenBootstrap</div> <div class="d2">Test sécurité</div> <div>Version : 2024-06-08_18:55</div> </div> </body> </html>
问题排查与修复方案
核心原因是*Tomcat 10基于Jakarta EE 9,而你的应用依赖的是Java EE(javax.包)组件,两者完全不兼容,以下是具体修复步骤:
1. 升级Spring Security版本
Spring Security 4.x不支持Jakarta EE,必须升级到5.7及以上版本(支持Jakarta的最低版本),修改pom.xml:
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.7.11.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.7.11.RELEASE</version> </dependency>
2. 替换Java EE依赖为Jakarta EE依赖
Tomcat10不再识别javax.servlet相关包,全部替换为jakarta.servlet对应依赖:
<!-- 替换原javax.servlet-api --> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>5.0.0</version> <scope>provided</scope> </dependency> <!-- 替换原JSTL依赖,移除所有javax.servlet.jsp.jstl相关依赖 --> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>jakarta.servlet.jsp.jstl</artifactId> <version>2.0.0</version> </dependency>
3. 更新web.xml至Jakarta EE规范
原web.xml是2.3版本,不符合Tomcat10的Servlet 5.0规范,修改为:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd" version="5.0"> <display-name>Archetype Created Web Application</display-name> </web-app>
4. 添加密码编码器(Spring Security 5+强制要求)
Spring Security 5+禁止明文密码,必须配置密码编码器,修改SecurityConfig.java:
package com.sharex30.security; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user").password("password").roles("USER") .passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { // 测试用,生产环境请替换为BCryptPasswordEncoder return NoOpPasswordEncoder.getInstance(); } }
生产环境推荐使用安全编码器:
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; // ... @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }此时密码需提前加密,比如
password("{bcrypt}$2a$10$EblZqNptyYvcLm/VwDCVAuBjzZOI7khzdyGPBr08PpIi0na624b8.")
5. 升级Java版本至1.8及以上
Spring Security 5.7+要求Java 8,修改pom.xml的编译版本:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties>
内容的提问来源于stack exchange,提问作者P. Gauthier
相关产品推荐
相关产品推荐

