如何在非Spring环境(含嵌入式Tomcat)中编程式使用Spring Security?
纯编程式配置Spring Security(无Spring注解 + 嵌入式Tomcat)
要在完全不依赖Spring注解、类路径扫描的前提下使用Spring Security,同时搭配纯编程式配置的嵌入式Tomcat,核心是手动构建Spring Security过滤器链并绑定到Tomcat的ServletContext,全程通过代码完成所有组件的初始化与注册。以下是完整的实现步骤和示例代码:
1. 依赖配置
确保项目引入必要的核心依赖(无需Spring Boot自动配置类):
<!-- 嵌入式Tomcat核心 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>10.1.18</version> </dependency> <!-- Spring Security核心 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>6.2.3</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>6.2.3</version> </dependency> <!-- Spring核心依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.1.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>6.1.4</version> </dependency>
2. 手动构建Spring Security过滤器链
不使用任何注解,直接通过HttpSecurity构建安全规则与过滤器链:
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; public class SecurityConfig { public SecurityFilterChain buildSecurityFilterChain(HttpSecurity http) throws Exception { // 配置URL授权规则 http.authorizeHttpRequests(auth -> auth .requestMatchers("/public/**").permitAll() // 公开路径无需认证 .anyRequest().authenticated() // 其余路径需认证 ); // 添加自定义过滤器(示例) http.addFilterBefore(new CustomSecurityFilter(), UsernamePasswordAuthenticationFilter.class); // 演示用:禁用CSRF(生产环境按需开启) http.csrf(csrf -> csrf.disable()); // 可按需添加认证方式,比如HTTP Basic: // http.httpBasic(); return http.build(); } } // 自定义过滤器示例 class CustomSecurityFilter implements javax.servlet.Filter { @Override public void doFilter(javax.servlet.ServletRequest req, javax.servlet.ServletResponse res, javax.servlet.FilterChain chain) throws java.io.IOException, javax.servlet.ServletException { System.out.println("[Custom Filter] 处理请求: " + ((javax.servlet.http.HttpServletRequest) req).getRequestURI()); chain.doFilter(req, res); } }
3. 嵌入式Tomcat的纯编程式配置与组件注册
手动启动Tomcat,初始化Spring上下文并注册Spring Security过滤器、自定义Servlet:
import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.startup.Tomcat; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.web.context.support.GenericWebApplicationContext; import javax.servlet.ServletRegistration; public class TomcatSecurityLauncher { public static void main(String[] args) throws LifecycleException { // 初始化嵌入式Tomcat Tomcat tomcat = new Tomcat(); tomcat.setPort(8080); Context tomcatContext = tomcat.addContext("", System.getProperty("java.io.tmpdir")); // 1. 初始化Spring Web上下文(无注解、无扫描) GenericWebApplicationContext springContext = new GenericWebApplicationContext(); // 注册SecurityConfig到Spring上下文 springContext.registerBean(SecurityConfig.class); springContext.refresh(); // 2. 注册Spring Security过滤器到Tomcat AbstractSecurityWebApplicationInitializer securityInitializer = new AbstractSecurityWebApplicationInitializer() { @Override protected org.springframework.web.context.WebApplicationContext createServletApplicationContext() { return springContext; } }; securityInitializer.onStartup(tomcatContext.getServletContext()); // 3. 注册自定义Servlet(无@WebServlet注解) javax.servlet.Servlet protectedServlet = new javax.servlet.http.HttpServlet() { @Override protected void doGet(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse resp) throws javax.servlet.ServletException, java.io.IOException { resp.getWriter().write("已通过认证,访问受保护资源"); } }; ServletRegistration.Dynamic servletReg = tomcatContext.addServlet("ProtectedServlet", protectedServlet); servletReg.addMapping("/private/**"); // 注册公开Servlet javax.servlet.Servlet publicServlet = new javax.servlet.http.HttpServlet() { @Override protected void doGet(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse resp) throws javax.servlet.ServletException, java.io.IOException { resp.getWriter().write("公开资源,无需认证"); } }; ServletRegistration.Dynamic publicServletReg = tomcatContext.addServlet("PublicServlet", publicServlet); publicServletReg.addMapping("/public/**"); // 启动Tomcat tomcat.start(); tomcat.getServer().await(); } }
关键细节说明
- Spring上下文:使用
GenericWebApplicationContext手动注册Bean,完全替代注解驱动的上下文,避免类路径扫描。 - Security过滤器注册:通过
AbstractSecurityWebApplicationInitializer将Spring Security的过滤器链注入Tomcat的ServletContext,无需依赖Spring的自动配置机制。 - Servlet注册:直接创建Servlet实例并通过Tomcat的API完成注册,完全抛弃
@WebServlet等注解。
验证运行
启动TomcatSecurityLauncher的main方法后:
- 访问
http://localhost:8080/public/test:直接返回公开内容,无拦截 - 访问
http://localhost:8080/private/test:若未配置认证方式(如HTTP Basic),会返回401未授权;若添加了http.httpBasic(),则会弹出认证窗口,输入正确凭证后可访问受保护内容
内容的提问来源于stack exchange,提问作者BBB
相关产品推荐
相关产品推荐

