ReactTS前端未向SpringBoot后端返回Cookie问题求助
我使用ReactTS+Vite+Mantine构建前端,SpringBoot作为后端,尝试通过Cookie实现会话管理时,前端无法向后端返回Cookie,同时求跨域环境下Spring Sessions的实现方案。
后端代码
登录接口(生成sessionID)
@PostMapping("/login") public ResponseEntity<User> loginUser( @RequestParam(value = "rmbr", defaultValue = "false") boolean rememberMe, @RequestBody User user ) { UserDatabase userDatabase = new UserDatabase(); User returnUser = userDatabase.getUserByUsernameOrEmail(user); if (returnUser.getUsername() == null || returnUser.getUsername().isEmpty()) { return new ResponseEntity<>(returnUser, HttpStatusCode.valueOf(462)); } if (BCrypt.checkpw(user.getPassword(), returnUser.getPassword())) { returnUser.setPassword(null); UUID sessionId = UUID.randomUUID(); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.add(HttpHeaders.SET_COOKIE,"SESSIONID=" + userDatabase.createCookie(sessionId.toString(), user, rememberMe)); return ResponseEntity .ok() .headers(responseHeaders) .body(returnUser); } return new ResponseEntity<>(new User(), HttpStatusCode.valueOf(463)); }
注:也曾尝试使用HttpServletResponse response方式创建Cookie对象,问题依旧。
获取会话详情接口
@GetMapping("/details") public ResponseEntity<User> getUserFromSession( @CookieValue("SESSIONID") String sessionId ) { UserDatabase userDatabase = new UserDatabase(); User user = userDatabase.getCookieUser(sessionId); user.setPassword(null); return new ResponseEntity<>(new User(), HttpStatusCode.valueOf(200)); }
调用该接口时,控制台报错:
2023-12-09T11:41:59.960+02:00 WARN 19748 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingRequestCookieException: Required cookie 'SESSIONID' for method parameter type String is not present]
Spring Security CORS配置
@Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); // 允许携带凭证(如Cookie) config.setAllowedOriginPatterns(List.of("*")); // 允许所有源 config.addAllowedHeader("*"); // 允许所有请求头 config.addAllowedMethod("*"); // 允许所有HTTP方法 source.registerCorsConfiguration("/**", config); return new CorsFilter(source); }
前端代码
登录函数
const handleLogin = async () => { const user: User = { email: (/^\S+@\S+$/.test(form.values.email) ? form.values.email : ''), username: (/^\S+@\S+$/.test(form.values.email) ? '' : form.values.email), password: form.values.password, profilePhoto: '', bio: '', role: 'user', orgName: '' }; try { const response = await fetch( serverIp + 'user/login', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(user), }); if (response.ok) { login(await response.json()) closeModal() } else if (response.status == 462) { setErrorMessage('User Does not Exist'); } else if (response.status == 463) { setErrorMessage('Invalid Password'); } } catch (error) { setErrorMessage('Could not connect to server, Please check internet connection') console.error('login fetch error', error) } finally { close() } }
页面加载时获取用户详情逻辑
const fetchUserDetails = async () => { try { const response = await fetch(`${serverIp}user/details`, { method: 'GET', credentials: 'include', }); if (response.ok) { const user = await response.json(); login(user); // 根据API响应更新用户信息 } else { console.error('No active sessions found for this device'); } } catch (error) { console.error('Error fetching user details:', error); } }; useEffect(() => { fetchUserDetails(); }, []);
已尝试操作
- 开启浏览器所有Cookie权限
- 分别用Spring Cookie和HttpServletResponse两种方式创建Cookie
- 功能在Postman中正常,但浏览器中异常
- 尝试设置HttpOnly为true、false或不设置
- 调整Cookie的MaxAge为-1或8小时
- 设置Cookie的Domain和Path属性
- 测试过localhost、127.0.0.1等不同地址
解决方案
一、修复Cookie不回传问题
- 前端登录请求添加
credentials: 'include'
登录接口的fetch请求未携带凭证配置,导致浏览器可能不保存Cookie或后续请求不携带。修改登录函数:
const response = await fetch( serverIp + 'user/login', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(user), credentials: 'include' // 新增此行 });
- 规范后端Cookie设置
避免直接拼接SET-COOKIE头,改用Cookie对象配置完整属性:
@PostMapping("/login") public ResponseEntity<User> loginUser( @RequestParam(value = "rmbr", defaultValue = "false") boolean rememberMe, @RequestBody User user, HttpServletResponse response // 注入response ) { // ... 原有逻辑省略 if (BCrypt.checkpw(user.getPassword(), returnUser.getPassword())) { returnUser.setPassword(null); UUID sessionId = UUID.randomUUID(); // 创建Cookie对象 Cookie sessionCookie = new Cookie("SESSIONID", sessionId.toString()); sessionCookie.setHttpOnly(true); // 建议开启,防范XSS攻击 sessionCookie.setSecure(false); // 本地开发设false,生产HTTPS环境设true sessionCookie.setDomain("localhost"); // 与前端域名一致,不要加端口 sessionCookie.setPath("/"); // 所有路径都可携带该Cookie sessionCookie.setMaxAge(rememberMe ? 8 * 3600 : -1); // 记住我则保存8小时,否则会话级Cookie response.addCookie(sessionCookie); return ResponseEntity.ok(returnUser); } // ... 原有逻辑省略 }
- 修正CORS配置
当allowCredentials设为true时,allowedOriginPatterns不能用*,需指定具体前端源:
@Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); // 替换为你的前端实际地址,比如http://localhost:5173 config.setAllowedOrigins(List.of("http://localhost:5173")); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); }
- 调整Cookie的SameSite属性
跨域场景下,若前端是POST请求(如登录),需设置SameSite为Lax或None(设None必须搭配Secure: true,即HTTPS环境):
sessionCookie.setSameSite("Lax"); // 或根据场景设None
二、跨域Spring Sessions实现方案
1. 引入依赖(以Redis存储为例)
在pom.xml中添加:
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2. 配置application.yml
spring: session: store-type: redis # 用Redis存储会话 timeout: 8h # 会话超时时间 redis: host: localhost # Redis地址 port: 6379 # Redis端口 server: servlet: session: cookie: http-only: true secure: false # 生产环境设true same-site: Lax # 跨域场景可设None(需HTTPS) domain: localhost # 与前端域名一致 path: /
3. 整合Spring Security(可选)
若使用Spring Security,无需手动生成SESSIONID,框架会自动处理会话:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .cors(Customizer.withDefaults()) // 启用CORS配置 .csrf(csrf -> csrf.disable()) // 开发环境可临时关闭,生产需配置 .authorizeHttpRequests(auth -> auth .requestMatchers("/user/login").permitAll() .anyRequest().authenticated() ) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) ); return http.build(); } }
4. 前端配置
确保所有请求都携带credentials: 'include',同之前的修复方案。
内容的提问来源于stack exchange,提问作者Johan Du Toit
相关产品推荐
相关产品推荐

