Spring Boot中如何让Redis存储的用户会话永不失效?
问题解决方案
一、修复Redis会话自动过期问题
你配置的server.servlet.session.timeout=-1仅控制Servlet容器层面的会话超时,Spring Session Redis有独立的超时配置,这是导致会话仍过期的核心原因。需补充以下配置:
spring.session.store-type=redis spring.session.redis.namespace=tc server.servlet.session.timeout=-1 # 关键配置:控制Redis中会话的存储超时,-1表示永不过期 spring.session.redis.timeout=-1 server.servlet.session.cookie.name=UISESSION server.servlet.session.cookie.http-only=true # 让Cookie本身永不过期,避免浏览器主动丢弃 server.servlet.session.cookie.max-age=-1
同时确认:
- Redis服务器未配置全局键过期策略,避免会话被Redis自动清理
- 项目中没有自定义RedisTemplate或SessionRepository覆盖超时设置
二、实现特定用户固定UISESSION值
要给特定用户分配固定会话ID,需自定义会话ID生成逻辑,并确保该会话永不过期,步骤如下:
1. 自定义会话ID生成器
import org.springframework.session.SessionIdGenerator; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; public class FixedSessionIdGenerator implements SessionIdGenerator { // 替换为你的特定用户标识(如用户名/用户ID) private static final String TARGET_USER_ID = "指定用户ID"; // 你想要的固定UISESSION值 private static final String FIXED_SESSION_ID = "your-fixed-uiseession-value"; @Override public String generateSessionId() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); // 仅为特定用户返回固定会话ID,其他用户用默认UUID生成 if (auth != null && TARGET_USER_ID.equals(auth.getName())) { return FIXED_SESSION_ID; } return java.util.UUID.randomUUID().toString(); } }
2. 配置会话仓库与生成器
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.session.data.redis.RedisIndexedSessionRepository; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.session.web.http.SessionIdGenerator; import org.springframework.data.redis.core.RedisTemplate; @Configuration @EnableRedisHttpSession public class SessionConfig { @Bean public SessionIdGenerator sessionIdGenerator() { return new FixedSessionIdGenerator(); } @Bean public RedisIndexedSessionRepository redisIndexedSessionRepository(RedisTemplate<String, Object> redisTemplate) { RedisIndexedSessionRepository repository = new RedisIndexedSessionRepository(redisTemplate); // 全局默认会话永不过期 repository.setDefaultMaxInactiveInterval(-1); return repository; } }
3. 登录时强制绑定固定会话
通过认证成功处理器,确保特定用户登录时直接使用固定会话(不存在则创建):
import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.session.Session; import org.springframework.session.SessionRepository; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Cookie; import java.util.Optional; @Component public class FixedSessionSuccessHandler implements AuthenticationSuccessHandler { private static final String TARGET_USER_ID = "指定用户ID"; private static final String FIXED_SESSION_ID = "your-fixed-uiseession-value"; private final SessionRepository<? extends Session> sessionRepository; public FixedSessionSuccessHandler(SessionRepository<? extends Session> sessionRepository) { this.sessionRepository = sessionRepository; } @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { if (TARGET_USER_ID.equals(authentication.getName())) { // 检查固定会话是否存在,不存在则创建并设置永不过期 Optional<? extends Session> existingSession = Optional.ofNullable(sessionRepository.findById(FIXED_SESSION_ID)); Session session = existingSession.orElseGet(() -> { Session newSession = sessionRepository.createSession(); newSession.setId(FIXED_SESSION_ID); newSession.setMaxInactiveInterval(-1); sessionRepository.save(newSession); return newSession; }); // 写入固定会话Cookie Cookie fixedCookie = new Cookie("UISESSION", FIXED_SESSION_ID); fixedCookie.setHttpOnly(true); fixedCookie.setMaxAge(-1); fixedCookie.setPath("/"); response.addCookie(fixedCookie); } // 其他用户按正常流程跳转 try { response.sendRedirect("/"); } catch (Exception e) { e.printStackTrace(); } } }
4. Spring Security中配置处理器
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private final FixedSessionSuccessHandler successHandler; public SecurityConfig(FixedSessionSuccessHandler successHandler) { this.successHandler = successHandler; } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .successHandler(successHandler) .and() .authorizeRequests() .anyRequest().authenticated(); } }
注意事项
- 固定会话ID存在会话劫持风险,建议为特定用户增加额外验证(如IP绑定、User-Agent校验)
- 测试前需清除Redis中旧的会话数据和浏览器缓存的Cookie,确保新配置生效
内容的提问来源于stack exchange,提问作者Joy
相关产品推荐
相关产品推荐

