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

Spring Session/Security:Redis会话未被正确删除问题排查

问题排查与修复方案

问题概述

搭建Spring OAuth客户端(BFF架构)对接Angular与Auth0时,登录会话可正常持久化到Redis,但注销操作仅清空会话内容,会话Key仍留存,且有序集合未被清理。

核心问题分析

  1. 自定义清理逻辑与Spring Session生命周期冲突
    代码中先调用sessionInformation.invalidate()清空会话属性/标记过期,再调用removeSession删除会话。但ReactiveRedisIndexedSessionRepository的deleteAndReturn方法依赖获取有效会话才能执行后续删除逻辑:

    • 若会话已被invalidate()清空属性或标记过期,getSession(id)会返回Mono.empty(),跳过所有删除步骤(删除sessionKey、索引、过期键等),仅触发空的成功信号,导致日志显示删除成功但实际Redis未清理。
  2. 未利用WebSession的默认清理机制
    Spring Session的WebSession.invalidate()方法会触发完整的会话清理流程,包括删除Redis中的会话Key、有序集合索引及过期键,自定义逻辑覆盖了这一默认流程,导致清理不彻底。

修复方案

方案1:改用WebSession默认invalidate方法

删除自定义SessionControl依赖,直接调用WebSession.invalidate()触发完整清理:

@Component
internal class SessionServerLogoutHandler(
    private val sessionProperties: SessionProperties,
    private val csrfProperties: CsrfProperties,
) : ServerLogoutHandler {

    private val logger = LoggerFactory.getLogger(SessionServerLogoutHandler::class.java)

    override fun logout(exchange: WebFilterExchange, authentication: Authentication?): Mono<Void> {
        return exchange.exchange.session
            .flatMap { session ->
                logger.info("Logging out: Invalidating User Session: ${session.id}")
                // 调用Spring Session默认清理逻辑
                session.invalidate()
                    .then(Mono.fromRunnable {
                        logger.info("Deleting Session Cookie: ${sessionProperties.SESSION_COOKIE_NAME}")
                        // 删除会话Cookie
                        val sessionCookie = ResponseCookie.from(sessionProperties.SESSION_COOKIE_NAME)
                            .maxAge(0)
                            .httpOnly(sessionProperties.SESSION_COOKIE_HTTP_ONLY)
                            .secure(sessionProperties.SESSION_COOKIE_SECURE)
                            .sameSite(sessionProperties.SESSION_COOKIE_SAME_SITE)
                            .path(sessionProperties.SESSION_COOKIE_PATH)
                            .domain(sessionProperties.SESSION_COOKIE_DOMAIN)
                            .build()
                        exchange.exchange.response.headers.add(
                            HttpHeaders.SET_COOKIE,
                            sessionCookie.toString()
                        )

                        logger.info("Deleting CSRF Cookie: ${csrfProperties.CSRF_COOKIE_NAME}")
                        // 删除CSRF Cookie
                        val csrfCookie = ResponseCookie.from(csrfProperties.CSRF_COOKIE_NAME)
                            .maxAge(0)
                            .httpOnly(csrfProperties.CSRF_COOKIE_HTTP_ONLY)
                            .secure(csrfProperties.CSRF_COOKIE_SECURE)
                            .sameSite(csrfProperties.CSRF_COOKIE_SAME_SITE)
                            .path(csrfProperties.CSRF_COOKIE_PATH)
                            .domain(csrfProperties.CSRF_COOKIE_DOMAIN)
                            .build()
                        exchange.exchange.response.headers.add(
                            HttpHeaders.SET_COOKIE,
                            csrfCookie.toString()
                        )
                    })
            }
    }
}

方案2:修复SessionControl删除逻辑

若需保留自定义SessionControl,直接跳过invalidate()步骤,调用删除方法:

fun invalidateSession(session: WebSession): Mono<Void> {
    val sessionId = session.id
    logger.info("Invalidating sessionId: $sessionId")
    // 直接执行删除操作,无需提前invalidate
    return webSessionStore.removeSession(sessionId)
        .doOnSuccess {
            logger.info("Session removed: $sessionId")
        }
        .doOnError { error ->
            logger.error("Error removing session: $sessionId", error)
        }
}

额外检查点

  • 确认ReactiveRedisIndexedSessionRepository的命名空间配置正确,删除操作针对Redis中实际存储的键前缀(默认spring:session:)。
  • 检查Redis操作日志,排除权限不足、连接超时等导致删除失败的外部因素。
  • 验证getSessionInformation方法是否正确获取RedisSession实例,避免因会话对象错误导致操作无效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:22:07