You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security 6登录异常求助:自定义FilterChain下的奇怪跳转现象

Spring Security 6 登录请求拦截与重定向问题解析

核心问题:loginProcessingUrl与自定义登录接口冲突

你遇到的问题本质是Spring Security的表单登录拦截机制和你自定义的/login1 POST接口发生了路径冲突:

  • 当配置.loginProcessingUrl("/login1")时,Spring Security会自动通过UsernamePasswordAuthenticationFilter拦截所有发往/login1的POST请求,自行接管登录验证流程——这意味着你UserController里的@PostMapping("/login1")根本不会被执行,请求提前被Security过滤器链拦截。此时若验证失败,Security会按配置的failureUrl("/login?error=true")重定向,但你的登录页实际路径是/login1,路径不匹配导致302循环重定向。
  • 改为.loginProcessingUrl("/login1!")时,Security过滤器仅拦截这个特殊路径,而你的表单提交目标是/login1,请求会正常落到自定义控制器接口上,由你手动调用AuthenticationManager完成验证,因此程序能正常运行。至于/login1!未在控制器定义也无影响,因为你实际并未触发该路径的请求,这个配置仅告知Security:若有请求到该路径则由其处理登录。

现有写法的隐患

你的实现绕开了Spring Security的标准表单登录流程,手动在控制器处理验证,会带来以下问题:

  • 重复造轮子:Security已封装完整的登录验证、异常处理、会话管理逻辑,手动实现易遗漏细节。
  • 状态与会话冲突:你配置了sessionCreationPolicy(SessionCreationPolicy.STATELESS)(无状态),但表单登录本质依赖会话,混合配置会导致偶尔的重定向异常(即你遇到的空白页/登录页重定向问题)。

正确解决方案

方案1:使用Spring Security标准表单登录流程(推荐)

删除控制器中的@PostMapping("/login1"),让Security完全接管登录验证:

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
    return http
            .csrf(config -> config.disable())
            .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/login1").permitAll() // 允许未认证访问登录页
                    .anyRequest().authenticated()
            )
            .formLogin(form -> form
                    .loginPage("/login1") // 指定自定义登录页路径
                    .loginProcessingUrl("/login1") // 表单提交路径,由Security处理
                    .defaultSuccessUrl("/hello", true) // 登录成功后跳转页面
                    .failureUrl("/login1?error=true") // 登录失败跳转回登录页并携带错误参数
            )
            .logout(logout -> logout.permitAll())
            // 表单登录依赖会话,不能使用STATELESS
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))
            .build();
}

同时修改登录页的错误提示参数,匹配上述failureUrl配置:

<div th:if="${param.error}">
    Invalid username and password.
</div>

方案2:坚持自定义登录接口(适合REST场景)

若想完全自定义登录逻辑,应采用REST风格接口,而非表单登录:

  1. 移除formLogin配置,改用无状态模式:
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
    return http
            .csrf(config -> config.disable())
            .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/login1").permitAll()
                    .anyRequest().authenticated()
            )
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .build();
}
  1. 保留控制器中的@PostMapping("/login1"),登录成功后返回令牌或手动处理跳转(无状态模式下不推荐跳转)。

偶尔重定向到空白页/登录页的原因

该问题源于你同时配置了STATELESS无状态会话和表单登录:

  • 表单登录成功后,Security会创建会话保存认证信息,但STATELESS禁止会话创建,导致认证状态无法持久化。
  • 后续请求时,Security无法识别已认证用户,会重定向到登录页;偶尔的空白页是会话状态不一致引发的异常。

解决办法是统一会话策略:表单登录使用IF_REQUIRED或ALWAYS,REST接口使用STATELESS。

内容的提问来源于stack exchange,提问作者Alexander Tupiza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 04:20:31