Spring Boot无Spring Security下向前端发送Cookie失效问题排查
问题分析与修复方案
1. 核心代码问题
addUser接口的错误
- HttpSession 获取方式错误:
request.getAttribute("session")无法正确获取会话,应该用request.getSession(true)(true表示不存在则创建),否则getSession会为null,调用getId()会直接抛空指针。 - Cookie 配置缺失:仅设置name和value不够,前端跨域场景下需要补充关键属性,否则浏览器会拒绝存储或携带Cookie。
- 请求参数接收问题:
@RequestBody String name如果前端传的是JSON格式(如{"name":"张三"}),会直接接收整个JSON字符串,而非单纯的姓名值,导致User对象的name属性错误。
修复后的addUser接口
@PostMapping("/addUser") public User addUser(@RequestBody Map<String, String> requestBody, HttpServletRequest request, HttpServletResponse response) { // 正确获取HttpSession,不存在则创建 HttpSession session = request.getSession(true); // 配置Cookie属性,适配前端跨域场景 Cookie cookie = new Cookie("sessionId", session.getId()); cookie.setPath("/"); // 允许所有路径访问Cookie cookie.setMaxAge(3600 * 24); // 设置有效期1天 cookie.setHttpOnly(true); // 防止XSS攻击,禁止JS读取Cookie cookie.setSameSite("Lax"); // 适配跨域场景,若完全跨域可设为None(需配合Secure属性) // 若前端是跨域请求,需设置domain为前端域名,比如cookie.setDomain("your-frontend-domain.com"); response.addCookie(cookie); sessionService.addSession(session); String sessionId = session.getId(); System.out.println("Session id is " + sessionId); // 从请求体中正确获取姓名 String name = requestBody.get("name"); User newUser = new User(name, sessionId); userService.addUser(newUser); return newUser; }
如果有规范的请求DTO,可替换为更清晰的写法:
// 定义请求DTO public class UserRequest { private String name; // getter和setter } // 接口接收参数 @PostMapping("/addUser") public User addUser(@RequestBody UserRequest userRequest, HttpServletRequest request, HttpServletResponse response) { String name = userRequest.getName(); // 后续逻辑同上 }
noOfUsers接口的优化
无需通过@RequestBody接收sessionId,直接从Cookie中读取即可;若要验证会话有效性,可结合sessionService做校验:
@PostMapping("/noOfUsers") public int userCount(HttpServletRequest request) { String sessionId = null; Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals("sessionId")) { sessionId = cookie.getValue(); System.out.println("Received sessionId from Cookie: " + sessionId); break; } } } // 可选:验证session是否有效 if (sessionId != null && !sessionService.isSessionValid(sessionId)) { throw new RuntimeException("Invalid session"); } return this.userService.noOfUser(); }
2. 前端请求配置问题
Postman能正常工作但前端不行,大概率是跨域请求未配置携带凭证:
- 若用axios,需设置
withCredentials: true:
axios.post('/addUser', { name: '张三' }, { withCredentials: true }) .then(res => console.log(res)) .catch(err => console.error(err)); axios.post('/noOfUsers', {}, { withCredentials: true }) .then(res => console.log(res)) .catch(err => console.error(err));
- 若用fetch,需设置
credentials: 'include':
fetch('/addUser', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: '张三' }), credentials: 'include' });
3. 跨域配置补充(若前后端域名不同)
Spring Boot需配置跨域允许携带凭证:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://your-frontend-domain.com") // 替换为前端实际域名 .allowedMethods("GET", "POST", "PUT", "DELETE") .allowCredentials(true) // 允许携带凭证(Cookie) .maxAge(3600); } }
注意:allowedOrigins不能设为*,否则allowCredentials(true)会失效,必须指定具体域名。
内容的提问来源于stack exchange,提问作者LazyCoder
相关产品推荐
相关产品推荐

