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

Servlet的doFilter与Spring Security监听器中Session ID不一致问题求助

嗨,我来帮你搞定这个Session ID不一致的问题!

问题根源分析

你遇到的这个问题,核心原因大概率是在单例的LoggedUserListener里直接注入了请求作用域的对象(HttpSession/HttpServletRequest)。毕竟@Service默认是单例Bean,而HttpSession和HttpServletRequest是跟着每个请求走的,直接注入的话,拿到的只会是第一次请求时的实例,根本不是当前认证请求对应的那个,Session ID自然对不上。

另外还有一种可能:Spring Security默认会做Session Fixation防护(防止会话固定攻击),比如认证成功后自动创建新Session。如果你的Filter在认证流程之前执行,拿到的是旧Session,而监听器是认证成功后触发的,此时已经切换到新Session,ID肯定不一样。

解决方案

1. 动态获取当前请求的Session(最推荐)

别再直接注入HttpSession或HttpServletRequest了,改用RequestContextHolder动态获取当前请求的上下文,这样每次触发事件时拿到的都是当前请求的真实Session:

@Service
@Transactional
public class LoggedUserListener implements ApplicationListener<AuthenticationSuccessEvent> {

    @Override
    public void onApplicationEvent(AuthenticationSuccessEvent event) {
        // 先拿到当前请求的上下文
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            // 非Web请求场景直接返回就行
            return;
        }
        HttpServletRequest request = attributes.getRequest();
        HttpSession session = request.getSession(); // 这里的Session就是当前请求对应的那个

        // 取出认证成功的用户信息
        Authentication authentication = event.getAuthentication();
        Object principal = authentication.getPrincipal();
        // 假设你的用户实体是User,强转后存入Session
        if (principal instanceof User) {
            session.setAttribute("loggedUser", principal);
        }
    }
}

2. 检查Session Fixation配置

如果你的Spring Security配置里开了sessionFixation().newSession(),认证成功后会创建新Session,这时候Filter(如果在认证前执行)拿到的旧Session和监听器的新Session ID肯定不同。你可以调整这个配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .sessionManagement(session -> session
                .sessionFixation()
                .migrateSession() // 把旧Session的属性迁移到新Session,既保留安全防护又不丢数据
                // 或者用none()关闭这个特性,但不推荐,毕竟是安全防护
            );
        return http.build();
    }
}

3. 调整自定义Filter的执行顺序

如果你的自定义Filter是在Spring Security的认证Filter之前跑的,那时候还没完成认证,Session可能还没被Spring Security处理。可以把Filter的顺序调到Spring Security认证Filter之后:

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<YourCustomFilter> yourCustomFilter() {
        FilterRegistrationBean<YourCustomFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new YourCustomFilter());
        // 设置在Spring Security核心Filter之后执行
        registrationBean.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE - 10);
        return registrationBean;
    }
}
总结

先试试第一种方案,这是最常见的问题根源。如果还不行,再检查Session Fixation配置和Filter的执行顺序,应该就能解决Session ID不一致的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:43:27