分布式会话管理实战:Session共享与状态管理的完整方案
2026/5/14 8:15:30 网站建设 项目流程

分布式会话管理实战:Session共享与状态管理的完整方案

大家好,我是迪哥。分布式系统中,会话管理是一个经典问题。从传统的 Session 复制到 Redis 共享,从 JWT Token 到 OAuth2,我们经历了多种方案的演进。今天就聊聊分布式会话管理的最佳实践。

会话管理方案对比

方案优点缺点适用场景
Session 复制简单同步开销大,扩展性差小集群
粘性会话性能好单点故障问题中等规模
Redis 共享高可用,易扩展需要额外依赖推荐
JWT Token无状态,易扩展Token 过期处理复杂API 网关
OAuth2标准协议实现复杂多系统集成

Redis Session 共享

Spring Session 配置

@Configuration @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) public class RedisSessionConfig { @Bean public LettuceConnectionFactory connectionFactory() { return new LettuceConnectionFactory("localhost", 6379); } }

自定义 Session 操作

@Service public class SessionService { @Autowired private RedisTemplate<String, Object> redisTemplate; private static final String SESSION_PREFIX = "session:"; public void setAttribute(String sessionId, String key, Object value) { redisTemplate.opsForHash().put(SESSION_PREFIX + sessionId, key, value); redisTemplate.expire(SESSION_PREFIX + sessionId, 30, TimeUnit.MINUTES); } public Object getAttribute(String sessionId, String key) { return redisTemplate.opsForHash().get(SESSION_PREFIX + sessionId, key); } public void invalidate(String sessionId) { redisTemplate.delete(SESSION_PREFIX + sessionId); } }

JWT Token 方案

Token 生成与验证

@Service public class JwtService { private static final String SECRET_KEY = "your-256-bit-secret"; private static final long EXPIRATION_TIME = 86400000; // 24小时 public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); return Jwts.builder() .setClaims(claims) .setSubject(userDetails.getUsername()) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } public boolean validateToken(String token, UserDetails userDetails) { final String username = extractUsername(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } }

Token 刷新机制

@Service public class TokenRefreshService { @Autowired private RedisTemplate<String, String> redisTemplate; private static final String REFRESH_TOKEN_PREFIX = "refresh:"; public void storeRefreshToken(String username, String refreshToken) { redisTemplate.opsForValue().set(REFRESH_TOKEN_PREFIX + username, refreshToken, 7, TimeUnit.DAYS); } public boolean validateRefreshToken(String username, String refreshToken) { String storedToken = redisTemplate.opsForValue().get(REFRESH_TOKEN_PREFIX + username); return refreshToken.equals(storedToken); } public void removeRefreshToken(String username) { redisTemplate.delete(REFRESH_TOKEN_PREFIX + username); } }

OAuth2 集成

Spring Security OAuth2 配置

@Configuration @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client-id") .secret("client-secret") .authorizedGrantTypes("password", "refresh_token") .scopes("read", "write") .accessTokenValiditySeconds(3600) .refreshTokenValiditySeconds(86400); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints.authenticationManager(authenticationManager); } }

会话安全

防止 Session 固定攻击

@Service public class SessionFixationProtectionFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpSession session = request.getSession(false); if (session != null && !isNewSession(session)) { String currentUser = (String) session.getAttribute("user"); if (currentUser != null) { // 登录成功后重新生成 Session ID session.invalidate(); request.getSession(true); } } filterChain.doFilter(request, response); } }

会话超时处理

@Configuration public class SessionTimeoutConfig { @Bean public FilterRegistrationBean<SessionTimeoutFilter> sessionTimeoutFilter() { FilterRegistrationBean<SessionTimeoutFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new SessionTimeoutFilter()); registration.addUrlPatterns("/*"); return registration; } } public class SessionTimeoutFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { HttpServletRequest req = (HttpServletRequest) request; HttpSession session = req.getSession(false); if (session != null && session.isNew()) { session.setMaxInactiveInterval(1800); // 30分钟 } chain.doFilter(request, response); } }

最佳实践清单

维度最佳实践
会话存储使用 Redis 共享,避免 Session 复制
Token 方案短时间 access token + 长时间 refresh token
安全启用 HTTPS,防止会话劫持
超时设置合理的超时时间,定期清理过期会话
监控监控会话数量、活跃用户数、超时率

说到会话管理,我家那只叫 Docker 的哈士奇最近学会了"会话保持"——只要我摸过它一次,它就会跟着我一整天,这粘性会话比我们的 Nginx 还强 😂

我是迪哥,我们下期再见!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询