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

Spring Boot OAuth2客户端集成Spring Session xAuthToken引发无限重定向循环

问题分析与解决方案

无限重定向的核心原因是:OAuth2授权码流程中,认证成功后的重定向请求里,浏览器不会自动携带x-auth-token请求头,导致客户端无法读取到之前存储在Session中的授权状态(比如state参数),进而认为用户未完成授权,反复跳转至授权服务器。

要实现用x-auth-token替代JSESSIONID,同时解决重定向循环,需要拆分处理OAuth2认证流程的状态存储和RestController的Session识别:

1. 替换OAuth2授权请求状态存储方式

默认的HttpSessionOAuth2AuthorizationRequestRepository依赖HttpSession传递授权状态,但切换到Header式Session解析后,重定向请求无法携带Session头,因此需要改用Cookie存储授权状态。

自定义Cookie-based授权请求仓库

class CookieBasedOAuth2AuthorizationRequestRepository : OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> {

    private val OAUTH2_AUTH_REQUEST_COOKIE = "oauth2_auth_request"
    private val REDIRECT_URI_COOKIE = "redirect_uri"
    private val COOKIE_EXPIRE_SECONDS = 180

    override fun loadAuthorizationRequest(request: HttpServletRequest): OAuth2AuthorizationRequest? {
        return getCookie(request, OAUTH2_AUTH_REQUEST_COOKIE)
            .map { ObjectMapper().readValue(it.value, OAuth2AuthorizationRequest::class.java) }
            .orElse(null)
    }

    override fun saveAuthorizationRequest(authRequest: OAuth2AuthorizationRequest?, request: HttpServletRequest, response: HttpServletResponse) {
        if (authRequest == null) {
            clearAuthRequestCookies(request, response)
            return
        }
        val cookieValue = ObjectMapper().writeValueAsString(authRequest)
        addCookie(response, OAUTH2_AUTH_REQUEST_COOKIE, cookieValue)
        request.getParameter("redirect_uri")?.let {
            addCookie(response, REDIRECT_URI_COOKIE, it)
        }
    }

    override fun removeAuthorizationRequest(request: HttpServletRequest, response: HttpServletResponse): OAuth2AuthorizationRequest? {
        return loadAuthorizationRequest(request).also {
            clearAuthRequestCookies(request, response)
        }
    }

    private fun clearAuthRequestCookies(request: HttpServletRequest, response: HttpServletResponse) {
        listOf(OAUTH2_AUTH_REQUEST_COOKIE, REDIRECT_URI_COOKIE).forEach { cookieName ->
            getCookie(request, cookieName)?.let {
                it.maxAge = 0
                response.addCookie(it)
            }
        }
    }

    private fun addCookie(response: HttpServletResponse, name: String, value: String) {
        val cookie = Cookie(name, value)
        cookie.path = "/"
        cookie.isHttpOnly = true
        cookie.maxAge = COOKIE_EXPIRE_SECONDS
        response.addCookie(cookie)
    }

    private fun getCookie(request: HttpServletRequest, name: String): Optional<Cookie> {
        return Optional.ofNullable(request.cookies)
            ?.filter { it.name == name }
            ?.firstOrNull()
            ?.let { Optional.of(it) } ?: Optional.empty()
    }
}

2. 配置Spring Security与Session解析器

在配置类中注册自定义授权仓库,并保留Header式Session解析器:

@Configuration
class SecurityConfig {

    // 注册Header式Session解析器
    @Bean
    fun sessionResolver(): HttpSessionIdResolver = HeaderHttpSessionIdResolver.xAuthToken()

    // 注册Cookie-based授权请求仓库
    @Bean
    fun authorizationRequestRepository(): OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> {
        return CookieBasedOAuth2AuthorizationRequestRepository()
    }

    // 配置Security Filter Chain
    @Bean
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http
            .authorizeHttpRequests { auth ->
                auth.anyRequest().authenticated()
            }
            .oauth2Login { oauth2 ->
                // 指定使用自定义的授权请求仓库
                oauth2.authorizationRequestRepository(authorizationRequestRepository())
            }
            .sessionManagement { session ->
                session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
            }
        return http.build()
    }
}

3. RestController请求处理

后续调用demo-client的RestController端点时,只需在请求头中携带x-auth-token,Spring Session即可通过该头识别Session,无需依赖JSESSIONID Cookie。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 20:56:20