基于Cookie的Spring Security前端会话维持问题求助
看起来你遇到了跨域请求下会话Cookie无法自动维护的典型问题——Postman会自动处理Cookie,但浏览器出于安全限制,在跨域场景下不会自动保存或携带Cookie,除非前后端都做了正确配置。咱们一步步来解决:
核心问题:跨域请求的Cookie限制
浏览器的同源策略会阻止跨域请求自动携带Cookie,同时默认不允许JS读取跨域响应的Set-Cookie头(尤其是Spring Session默认的HttpOnly Cookie,这是安全设置)。这就是你看到document.cookie为空、response.headers.get('Set-Cookie')为null的原因——不是Cookie没返回,是浏览器不让你读,也没自动存。
解决方案:前后端配合开启跨域凭证支持
1. 后端Spring Security配置CORS
你需要在Spring Security中明确配置跨域规则,允许前端域名的请求携带凭证。修改你的SpringSecurityConfig:
@EnableWebSecurity @Configuration public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AuthenticationProviderService authenticationProviderService; // 新增CORS配置Bean @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); // 替换成你的前端实际域名+端口,比如http://localhost:3000,不能用*(带凭证不允许通配符) configuration.setAllowedOrigins(Arrays.asList("http://your-frontend-url:port")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("*")); // 关键:允许携带凭证(Cookie) configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } @Override protected void configure(HttpSecurity http) throws Exception { http .cors() // 启用CORS配置 .and() .authorizeRequests() .antMatchers("/customer/register").permitAll() .anyRequest().fullyAuthenticated() .and() .formLogin() .permitAll() .defaultSuccessUrl("/customer/home", false) .and() .logout() .permitAll() .and() .httpBasic(); http.csrf().disable(); } //[ . . . ] }
2. 前端React请求添加凭证参数
修改你的fetch请求,加上credentials: 'include',告诉浏览器在跨域请求中携带/保存Cookie:
const mw = store => next => action => { if(action.type == 'SUBMIT_LOGIN_USER') { var payload = { username: action.user.username, password: action.user.password }; // Build formData object. let formData = new FormData(); formData.append('username', action.user.username); formData.append('password', action.user.password); return fetch('http://192.168.0.34:8080/login', { method: 'POST', body: formData, credentials: 'include' // 新增这一行,关键配置! }).then( r => (r) ) .then(function(response) { // 浏览器会自动保存HttpOnly Cookie,无需手动读取Set-Cookie console.log(document.cookie) // 若Cookie非HttpOnly,此处会显示会话Cookie(建议保持HttpOnly) next(action) }) .catch(function(err) { console.info(err); }); } else { next(action) } }
3. 后续请求的注意事项
登录成功后,所有后续向后端发起的API请求(比如跳转后的GET /customer/home)都需要加上credentials: 'include',这样浏览器才会自动携带会话Cookie,后端就能识别用户身份,不会返回403。
关于是否改用认证令牌(JWT)
Cookie-Session模式完全可以正常工作,而且默认的HttpOnly Cookie比前端存储JWT更安全(能避免XSS攻击窃取令牌)。如果你的系统是单体应用,Cookie模式足够用;如果是分布式微服务架构,JWT可能更适合(无需服务器存储会话)。但当前问题的核心是跨域配置,不是方案选型——先把Cookie模式跑通再考虑是否切换。
额外说明
- Spring Session默认的会话Cookie是HttpOnly的,这是安全最佳实践,所以JS无法读取它,但浏览器会自动在请求中携带,完全不影响会话维护。
- 不要为了让JS读取Cookie而关闭HttpOnly,这会引入XSS风险。
内容的提问来源于stack exchange,提问作者bohemian

