You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 19:50:22