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

Spring应用自定义AuthenticationSuccessHandler重定向异常排查与解决

解决Spring Security一次性令牌(OTT)认证成功后重定向404问题

问题描述

在Spring应用中实现一次性令牌(OTT)认证流程的自定义AuthenticationSuccessHandler时遇到异常行为:

  • 向http://localhost:8080/login/ott发送包含client-id、token、token-type参数的POST请求
  • 成功认证时,期望自定义处理器设置Authorization请求头,并根据token-type执行重定向
  • 实际返回404 Not Found响应,响应路径仍停留在/login/ott
  • 怀疑是服务器端转发逻辑导致该问题

需求:修改重定向逻辑,避免响应中包含原请求路径,不硬编码路径,充分利用Spring Security功能。

当前自定义处理器代码:

@Component
class OneTimeTokenAuthenticationSuccessHandler : AuthenticationSuccessHandler {
    override fun onAuthenticationSuccess(
        request: HttpServletRequest,
        response: HttpServletResponse,
        authentication: Authentication
    ) {
        // getting email in authentication.name
        response.setHeader(HttpHeaders.AUTHORIZATION, request.getParameter("client-id"))
        val tokenType = when(request.getParameter("token-type")) {
            TokenType.REGISTER.name -> TokenType.REGISTER
            TokenType.PASSWORD_RESET.name -> TokenType.PASSWORD_RESET
            else -> throw IllegalArgumentException("Invalid token type")
        }
        request.getRequestDispatcher(tokenType.successRedirectionUrl).forward(request, response)
    }
}

解决方案

问题根源在于request.getRequestDispatcher().forward()是服务器端转发,会保留原请求的URL路径(即/login/ott),如果目标路径没有对应映射,就会返回404。正确做法是使用客户端重定向,同时结合Spring Security提供的工具类规范流程。

修改后的代码

import org.springframework.security.web.DefaultRedirectStrategy
import org.springframework.security.web.RedirectStrategy
import org.springframework.stereotype.Component
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.http.HttpHeaders

@Component
class OneTimeTokenAuthenticationSuccessHandler : AuthenticationSuccessHandler {

    // 使用Spring Security标准化的重定向处理类
    private val redirectStrategy: RedirectStrategy = DefaultRedirectStrategy()

    override fun onAuthenticationSuccess(
        request: HttpServletRequest,
        response: HttpServletResponse,
        authentication: Authentication
    ) {
        // 设置Authorization请求头
        response.setHeader(HttpHeaders.AUTHORIZATION, request.getParameter("client-id"))
        
        val tokenType = when(request.getParameter("token-type")) {
            TokenType.REGISTER.name -> TokenType.REGISTER
            TokenType.PASSWORD_RESET.name -> TokenType.PASSWORD_RESET
            else -> throw IllegalArgumentException("Invalid token type")
        }

        // 执行客户端重定向,更新浏览器地址栏路径
        redirectStrategy.sendRedirect(request, response, tokenType.successRedirectionUrl)
    }
}

关键修改说明

  • 替换转发为客户端重定向:sendRedirect()会让浏览器发起新的GET请求到目标路径,响应URL会更新为目标路径,彻底脱离原请求的/login/ott路径,解决404问题。
  • 利用Spring Security工具类:RedirectStrategy内部处理了URL编码、上下文路径自动拼接等细节,避免硬编码路径时出现的错误,符合Spring Security的设计规范。
  • 验证目标路径映射:确保tokenType.successRedirectionUrl对应的路径在应用中存在有效的控制器或静态资源映射,这是解决404的基础前提。

额外配置优化

可以在SecurityFilterChain中整合自定义处理器,让认证流程更规范:

import org.springframework.context.annotation.Bean
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.SecurityFilterChain

@Bean
fun filterChain(http: HttpSecurity, oneTimeTokenAuthSuccessHandler: OneTimeTokenAuthenticationSuccessHandler): SecurityFilterChain {
    return http
        .authorizeHttpRequests { auth ->
            auth.requestMatchers("/login/ott").permitAll()
            // 添加其他授权规则
        }
        .formLogin { form ->
            form.loginProcessingUrl("/login/ott")
                .successHandler(oneTimeTokenAuthSuccessHandler)
        }
        .build()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 07:16:11