Spring为何持续返回302状态码重定向至登录页面?
问题:Spring Security 方法级权限校验未生效,访问根路径返回302重定向
我想实现默认锁定所有资源,仅按需开放的安全策略:除少数白名单端点外,所有请求启用方法级安全校验。但目前遇到问题:
- 若把配置中的
.anyRequest.authenticated()改成.anyRequest.permitAll(),方法级安全能正常工作,但需要给每个方法/类加注解锁访问,不符合默认锁定的最佳实践。 - 按照资料里的方案用
.anyRequest.authenticated()配合@PreAuthorize按需开放时,访问根路径/始终返回302重定向到登录页,而不是预期的权限校验失败的4xx状态码。
环境信息
- Java 24 + Spring Boot 3.4.5
控制器代码
@Controller @RequestMapping("/") public class AppController { @GetMapping @PreAuthorize("hasRole('ANONYMOUS')") public String home() { return "home"; // 模板文件在 classpath:/templates } }
安全配置
@EnableWebSecurity(debug = true) @EnableMethodSecurity @Configuration public class SecurityConfig { @Bean public SecurityFilterChain filter(HttpSecurity http) throws Exception { var whitelist = new String[]{ "/styles/**", "/listing-images/**", "/thumbnail-images/**", "/login", "/favicon.ico" }; return http .authorizeHttpRequests(a -> a .requestMatchers(whitelist).permitAll() .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()) .build(); } }
Application.yaml配置
spring: datasource: url: jdbc:postgresql://localhost:9056/db username: my_user password: my_password logging: level: org.springframework.security: debug server: port: 8090
依赖
- Spring Boot DevTools
- Spring Web
- Thymeleaf
- Spring Security
- JDBC API
- PostgreSQL Driver
- Validation
文件夹结构

访问根路径后的日志信息
2025-05-15T00:07:38.329-06:00 INFO 2958139 --- [ restartedMain] c.t.n.NewMarketplaceApplication : Starting NewMarketplaceApplication using Java 24 with PID 2958139 (/home/PcUser/Documents/dev/java/new-marketplace/target/classes started by PcUser in /home/PcUser/Documents/dev/java/new-marketplace) 2025-05-15T00:07:38.331-06:00 INFO 2958139 --- [ restartedMain] c.t.n.NewMarketplaceApplication : No active profile set, falling back to 1 default profile: "default" 2025-05-15T00:07:38.362-06:00 INFO 2958139 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable 2025-05-15T00:07:38.362-06:00 INFO 2958139 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG' 2025-05-15T00:07:39.068-06:00 INFO 2958139 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http) 2025-05-15T00:07:39.076-06:00 INFO 2958139 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2025-05-15T00:07:39.076-06:00 INFO 2958139 --- [ restartedMain] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.40] 2025-05-15T00:07:39.096-06:00 INFO 2958139 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2025-05-15T00:07:39.096-06:00 INFO 2958139 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 734 ms 2025-05-15T00:07:39.186-06:00 WARN 2958139 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration : Using generated security password: 5a4a254a-cabe-43df-85a2-de1fd0d9a375 This generated password is for development use only. Your security configuration must be updated before running your application in production. 2025-05-15T00:07:39.200-06:00 INFO 2958139 --- [ restartedMain] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name inMemoryUserDetailsManager 2025-05-15T00:07:39.393-06:00 DEBUG 2958139 --- [ restartedMain] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with filters: DisableEncodeUrlFilter, WebAsyncManagerIntegrationFilter, SecurityContextHolderFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, UsernamePasswordAuthenticationFilter, DefaultResourcesFilter, DefaultLoginPageGeneratingFilter, DefaultLogoutPageGeneratingFilter, RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter, AnonymousAuthenticationFilter, ExceptionTranslationFilter, AuthorizationFilter 2025-05-15T00:07:39.608-06:00 INFO 2958139 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729 2025-05-15T00:07:39.629-06:00 INFO 2958139 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8090 (http) with context path '/' 2025-05-15T00:07:39.635-06:00 INFO 2958139 --- [ restartedMain] c.t.n.NewMarketplaceApplication : Started NewMarketplaceApplication in 1.587 seconds (process running for 1.967) 2025-05-15T00:08:32.604-06:00 INFO 2958139 --- [nio-8090-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2025-05-15T00:08:32.604-06:00 INFO 2958139 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2025-05-15T00:08:32.605-06:00 INFO 2958139 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms 2025-05-15T00:08:32.616-06:00 DEBUG 2958139 --- [nio-8090-exec-1] o.s.security.web.FilterChainProxy : Securing GET / 2025-05-15T00:08:32.621-06:00 DEBUG 2958139 --- [nio-8090-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2025-05-15T00:08:32.634-06:00 DEBUG 2958139 --- [nio-8090-exec-1] o.s.s.w.s.HttpSessionRequestCache : Saved request http://localhost:8090/?continue to session 2025-05-15T00:08:32.634-06:00 DEBUG 2958139 --- [nio-8090-exec-1] o.s.s.web.DefaultRedirectStrategy : Redirecting to http://localhost:8090/login 2025-05-15T00:08:32.650-06:00 DEBUG 2958139 --- [nio-8090-exec-2] o.s.security.web.FilterChainProxy : Securing GET /login 2025-05-15T00:08:32.742-06:00 DEBUG 2958139 --- [nio-8090-exec-3] o.s.security.web.FilterChainProxy : Securing GET /default-ui.css 2025-05-15T00:08:32.778-06:00 DEBUG 2958139 --- [nio-8090-exec-4] o.s.security.web.FilterChainProxy : Securing GET /favicon.ico 2025-05-15T00:08:32.779-06:00 DEBUG 2958139 --- [nio-8090-exec-4] o.s.security.web.FilterChainProxy : Secured GET /favicon.ico 2025-05-15T00:08:32.787-06:00 DEBUG 2958139 --- [nio-8090-exec-4] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
请求状态截图

解决方案
问题根源
Spring Security的过滤器链优先级高于方法级安全校验。配置中.anyRequest().authenticated()要求所有非白名单请求必须已认证,匿名访问时未通过这一层校验,直接被ExceptionTranslationFilter拦截触发登录重定向(302),根本没机会执行控制器上的@PreAuthorize注解逻辑。
另外,hasRole('ANONYMOUS')用法有误:Spring Security默认给匿名用户的是ROLE_ANONYMOUS角色,hasRole会自动添加ROLE_前缀,实际判断的是ROLE_ANONYMOUS,更规范的写法是用isAnonymous()。
修复步骤
1. 调整安全配置,让方法级校验生效
将根路径/加入白名单,允许匿名访问,确保请求能到达控制器执行@PreAuthorize校验:
@EnableWebSecurity(debug = true) @EnableMethodSecurity @Configuration public class SecurityConfig { @Bean public SecurityFilterChain filter(HttpSecurity http) throws Exception { var whitelist = new String[]{ "/", // 新增根路径到白名单 "/styles/**", "/listing-images/**", "/thumbnail-images/**", "/login", "/favicon.ico" }; return http .authorizeHttpRequests(a -> a .requestMatchers(whitelist).permitAll() .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()) .build(); } }
2. 修正@PreAuthorize表达式
把hasRole('ANONYMOUS')改成isAnonymous(),符合Spring Security规范:
@Controller @RequestMapping("/") public class AppController { @GetMapping @PreAuthorize("isAnonymous()") public String home() { return "home"; } }
3. (可选)自定义权限错误响应
如果希望匿名访问不符合权限时返回403状态码,可配置异常处理:
return http .authorizeHttpRequests(a -> a .requestMatchers(whitelist).permitAll() .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()) .exceptionHandling(e -> e .accessDeniedHandler((request, response, ex) -> { response.setStatus(HttpServletResponse.SC_FORBIDDEN); // Thymeleaf场景可跳转403错误页,API场景可返回JSON response.sendRedirect("/error/403"); }) ) .build();
内容的提问来源于stack exchange,提问作者FakeIfe
相关产品推荐
相关产品推荐

