1. 为什么需要Cookie和Session在Web开发中HTTP协议本身是无状态的这意味着服务器无法自动识别两次请求是否来自同一个用户。想象一下每次刷新页面都需要重新登录的网站会有多糟糕。这就是为什么我们需要Cookie和Session这对黄金搭档。Cookie是存储在用户浏览器中的小型文本数据而Session则是存储在服务器端的用户状态信息。它们协同工作就像电影院的门票系统Cookie是你的票根包含座位号而Session是影院内部的座位表记录谁坐在哪个位置。重要提示虽然Cookie和Session经常一起使用但它们解决的问题不同。Cookie主要用于客户端状态保持Session则用于服务端状态管理。2. Spring Boot中的Cookie实战2.1 创建和发送Cookie在Spring Boot中操作Cookie非常简单。以下是一个完整的登录接口示例它会在认证成功后设置CookiePostMapping(/login) public ResponseEntityString login(RequestBody LoginRequest request, HttpServletResponse response) { if (authenticate(request)) { // 创建Cookie Cookie cookie new Cookie(user_token, generateToken(request.getUsername())); // 设置关键属性 cookie.setMaxAge(7 * 24 * 60 * 60); // 7天有效期 cookie.setPath(/); // 全站可用 cookie.setHttpOnly(true); // 防止XSS攻击 cookie.setSecure(true); // 仅HTTPS传输 // 添加到响应 response.addCookie(cookie); return ResponseEntity.ok(登录成功); } return ResponseEntity.status(401).body(认证失败); }2.2 Cookie的安全配置在实际项目中必须关注Cookie的安全性HttpOnly防止JavaScript读取防范XSS攻击Secure仅通过HTTPS传输防止中间人攻击SameSite现代浏览器的重要安全特性Spring Boot 2.4支持// SameSite配置示例需要Spring Boot 2.4 Bean public WebServerFactoryCustomizerTomcatServletWebServerFactory cookieProcessorCustomizer() { return factory - factory.addContextCustomizers(context - { context.setCookieProcessor(new LegacyCookieProcessor() { Override public void parseCookieHeader(org.apache.tomcat.util.http.Rfc6265CookieProcessor processor) { processor.setSameSiteCookies(Lax); } }); }); }2.3 读取和验证Cookie从请求中获取Cookie并验证GetMapping(/profile) public ResponseEntityUserProfile getProfile(CookieValue(value user_token, required false) String token) { if (token null || !validateToken(token)) { return ResponseEntity.status(401).build(); } String username extractUsernameFromToken(token); UserProfile profile userService.getProfile(username); return ResponseEntity.ok(profile); }3. Spring Session深度解析3.1 Session工作原理Spring Session的底层机制可以用这张表格说明组件作用默认实现SessionRepository管理Session的CRUDMapSessionRepositorySessionIdResolver解析Session IDCookieSessionIdResolverHttpSessionStrategySession传输策略CookieHttpSessionStrategy当请求到达时Spring Session会通过SessionIdResolver从请求中提取Session ID使用SessionRepository加载对应Session将Session存入SecurityContextHolder请求处理完成后保存Session变更3.2 分布式Session方案在微服务架构中我们需要分布式Session解决方案。以下是几种常见方案的对比方案优点缺点适用场景Redis高性能支持持久化需要额外基础设施大多数分布式系统JDBC无需额外中间件性能较差小型系统已有数据库Hazelcast内存速度快集群管理复杂内存密集型应用JWT无状态扩展性好无法主动失效前后端分离项目Redis配置示例Configuration EnableRedisHttpSession public class SessionConfig extends AbstractHttpSessionApplicationInitializer { Bean public LettuceConnectionFactory connectionFactory() { return new LettuceConnectionFactory(); } }3.3 Session超时与并发控制实际项目中经常需要精细控制SessionConfiguration public class SessionManagementConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ConcurrentSessionControlInterceptor( sessionRegistry())).addPathPatterns(/api/**); } Bean public SessionRegistry sessionRegistry() { return new SessionRegistryImpl(); } Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); } }然后在application.properties中配置server.servlet.session.timeout1800 # 30分钟 spring.session.redis.flush-modeon_save spring.session.redis.namespacemyapp:session4. 登录状态保持的最佳实践4.1 记住我(Remember-Me)实现自动登录功能需要特别注意安全性Configuration EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http.rememberMe() .key(uniqueAndSecret) .tokenValiditySeconds(86400 * 30) // 30天 .rememberMeParameter(remember-me) .rememberMeCookieName(remember-me) .userDetailsService(userDetailsService()); } }安全增强建议使用持久化token而非简单加密每次验证后更新token提供全局注销功能4.2 防御会话固定攻击会话固定(Session Fixation)是常见的安全威胁Spring Security提供了内置防护Override protected void configure(HttpSecurity http) throws Exception { http.sessionManagement() .sessionFixation().migrateSession() // 登录后创建新Session .maximumSessions(1) .maxSessionsPreventsLogin(false) .expiredUrl(/login?expired); }4.3 移动端适配方案对于APP等非浏览器客户端通常采用Token方案Configuration public class MultiAuthSecurityConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers(/api/**).authenticated() .and() .apply(new TokenAuthConfigurer()) .tokenValidator(apiTokenValidator()); } Bean public TokenValidator apiTokenValidator() { return token - { // 实现token验证逻辑 return new UsernamePasswordAuthenticationToken( parseUserFromToken(token), null, parseAuthoritiesFromToken(token)); }; } }5. 常见问题排查指南5.1 Cookie未生效的排查步骤检查浏览器是否禁用了Cookie确认域名和路径设置正确检查Secure标记与协议匹配HTTPS必须验证SameSite配置是否与跨域需求冲突查看响应头中是否确实包含Set-Cookie调试技巧使用Chrome开发者工具的Application Cookies面板实时观察Cookie变化5.2 Session丢失问题分析当遇到神秘的Session丢失时按这个流程排查检查服务器日志是否有异常确认所有请求都携带了正确的Session ID验证Session存储后端如Redis是否正常运行检查Session超时设置是否过短排查是否有代码手动调用了session.invalidate()5.3 分布式环境下的同步问题在集群环境中可能会遇到幽灵Session一个节点创建的Session在其他节点不可见解决方案确保所有节点时钟同步检查网络延迟是否过高并发修改冲突使用SessionAttributes时要特别小心考虑使用乐观锁机制RestController SessionAttributes(shoppingCart) public class CartController { PostMapping(/addItem) public String addItem(ModelAttribute(shoppingCart) ShoppingCart cart, RequestParam Item item, SessionStatus status) { // 操作购物车 if (cart.isComplete()) { status.setComplete(); // 明确标记Session完成 } return success; } }我在实际项目中发现合理组合使用Cookie和Session可以构建既安全又用户友好的认证系统。对于关键业务系统建议定期审计Session使用情况并建立完整的会话生命周期监控。