Spring Boot结合Spring Security实现每次请求刷新Cookie有效期及持久化登录
嘿,这个需求我刚好在项目里实现过,结合Spring Boot + Spring Security来搞定其实挺清晰的,咱们一步步来:
核心思路拆解
首先得明确两个关键点:
- 默认情况下,浏览器的
JSESSIONIDCookie是会话级的(maxAge=-1),关闭浏览器就会被删除,所以得先把它改成持久化Cookie,设置初始过期时间为1小时; - 要实现“每次请求刷新过期时间”,就得在用户每次发起有效请求时,重新设置Cookie的过期时间,让它从当前时间再往后延1小时。
具体实现步骤
1. 配置Spring Security,让Session Cookie持久化
首先通过Spring Security的CookieSerializer来配置JSESSIONID的属性,把它改成持久化的,同时设置初始超时时间。另外别忘了在配置文件里设置Session的超时时间,保持和Cookie一致。
配置文件(application.properties)
# Session超时时间设置为1小时 server.servlet.session.timeout=3600s
Security配置类(Spring Security 5.7+ 新写法)
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // 权限配置,根据你的实际需求调整 .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) // 登录方式,这里用表单登录做示例,你可以换成自己的登录逻辑 .formLogin(form -> form .permitAll() ) // Session管理配置,防止会话固定攻击,控制最大会话数 .sessionManagement(session -> session .sessionFixation().migrateSession() .maximumSessions(1) ); return http.build(); } // 配置JSESSIONID Cookie的属性,设置持久化和初始超时 @Bean public CookieSerializer cookieSerializer() { DefaultCookieSerializer serializer = new DefaultCookieSerializer(); serializer.setCookieName("JSESSIONID"); serializer.setCookiePath("/"); // Cookie生效路径,一般设为根路径 serializer.setCookieMaxAge(3600); // 初始过期时间1小时(秒) // 如果是生产环境有域名需求,加上下面这行,本地开发可以注释掉 // serializer.setDomainName("your-domain.com"); return serializer; } }
如果你的项目还在用旧的WebSecurityConfigurerAdapter,可以这么写:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .permitAll() .and() .sessionManagement() .sessionFixation().migrateSession() .maximumSessions(1); } @Bean public CookieSerializer cookieSerializer() { DefaultCookieSerializer serializer = new DefaultCookieSerializer(); serializer.setCookieName("JSESSIONID"); serializer.setCookiePath("/"); serializer.setCookieMaxAge(3600); return serializer; } }
2. 实现请求拦截器,每次请求刷新Cookie过期时间
写一个拦截器,在用户每次发起请求时(仅限已登录用户),找到JSESSIONID Cookie,重新设置它的过期时间,这样就能实现“活跃时永不超时,停1小时才过期”的效果。
@Component public class SessionRefreshInterceptor implements HandlerInterceptor { // 从配置文件读取Session超时时间,默认1小时 @Value("${server.servlet.session.timeout:3600}") private int sessionTimeoutSeconds; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 只处理已登录用户的请求,未登录的不用管 if (request.getUserPrincipal() != null) { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if ("JSESSIONID".equals(cookie.getName())) { // 刷新Cookie的过期时间,从当前时间往后延1小时 cookie.setMaxAge(sessionTimeoutSeconds); cookie.setPath("/"); // 必须和原来的Cookie路径一致 // 生产环境记得加上域名 // cookie.setDomain("your-domain.com"); response.addCookie(cookie); break; } } } } return true; } }
3. 注册拦截器到Spring Boot中
最后要把刚才写的拦截器注册到WebMvc配置里,让它生效。
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private SessionRefreshInterceptor sessionRefreshInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(sessionRefreshInterceptor) .addPathPatterns("/**") // 拦截所有请求 // 排除不需要拦截的路径,比如登录、登出、静态资源等 .excludePathPatterns("/login", "/logout", "/static/**", "/error"); } }
注意事项
- 确保Cookie的
path和domain设置正确,不然可能会生成多个JSESSIONIDCookie,导致会话混乱; - 如果你的项目用了Redis等分布式Session,记得同步配置Redis中Session的超时时间,保持和Cookie一致;
- 测试的时候,关闭浏览器再打开,检查
JSESSIONIDCookie是否还存在,并且每次请求后过期时间是否被刷新。
内容的提问来源于stack exchange,提问作者ArslanAnjum
相关产品推荐
相关产品推荐

