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
相关产品推荐
相关产品推荐

