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

SpringBoot+SPA前后端分离下如何持久化登录状态?

问题

我使用SpringBoot作为后端、SPA作为前端,希望登录成功后记住当前用户的userId与权限,通过访问/current接口获取用户信息。我的Controller与SecurityConfig代码如下:

Controller代码

public RespResult<Object> login() {
    List<SimpleGrantedAuthority> permissions = new ArrayList<>();
    permissions.add(new SimpleGrantedAuthority("admin"));
    Long userId = (long) 122;

    SecurityContext context = SecurityContextHolder.createEmptyContext();
    Authentication authentication =
        new UsernamePasswordAuthenticationToken(userId, null, permissions);
    context.setAuthentication(authentication);
    SecurityContextHolder.setContext(context);

    return new RespResult<Object>(200, "", null);
}

@GetMapping("/current")
public RespResult<Object> getCurrentUseer() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    Long userId = Long.parseLong(authentication.getPrincipal().toString());
    System.out.println(userId);

    return new RespResult<Object>(200, "", null);
}

SecurityConfig代码

@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class DefaultSecurityConfig {

  @Bean
  public WebSecurityCustomizer webSecurityCustomizer() {
    String[] antMatchersAnonymous = {"/public/**", "/assets/**", "/webjars/**"};
    return web -> web.ignoring()
        .requestMatchers(antMatchersAnonymous)
        .requestMatchers(HttpMethod.OPTIONS);
  }

  @Bean
  public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http.csrf().disable();
    return http.build();
  }
}

目前我可以正常访问登录控制器,但发现SpringBoot未向前端设置Cookie,导致无法记住当前用户的userId,请问该如何解决?


解决方法

问题核心是你手动设置的SecurityContext仅存在于当前请求线程,未持久化到会话或Cookie,导致后续请求无法获取用户信息。需配置Spring Security的会话管理,让它自动维护登录状态并生成会话Cookie。

1. 启用会话管理配置

修改DefaultSecurityConfig中的defaultSecurityFilterChain方法,添加会话管理策略:

@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .sessionManagement(session -> session
            // 按需创建会话,登录成功后自动生成JSESSIONID Cookie
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
        );
    return http.build();
}

SessionCreationPolicy.IF_REQUIRED为默认策略,当认证成功后,Spring Security会自动将SecurityContext存入会话,并向客户端发送JSESSIONID Cookie。

2. 规范登录接口实现

无需手动操作SecurityContextHolder,改用AuthenticationManager完成认证,让Spring Security自动维护会话:

@Autowired
private AuthenticationManager authenticationManager;

public RespResult<Object> login() {
    List<SimpleGrantedAuthority> permissions = new ArrayList<>();
    permissions.add(new SimpleGrantedAuthority("admin"));
    Long userId = 122L;

    // 通过AuthenticationManager完成认证
    Authentication authentication = authenticationManager.authenticate(
        new UsernamePasswordAuthenticationToken(userId, null, permissions)
    );

    // 认证成功后,Spring Security自动处理会话与Cookie
    return new RespResult<>(200, "登录成功", null);
}

如果是从数据库查询用户权限的真实场景,这种方式更符合Spring Security规范,也能自动触发会话创建。

3. 跨域场景配置(SPA与后端跨域时)

若前端SPA和后端部署在不同域名下,需配置CORS允许携带Cookie:

后端CORS配置

@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .cors(cors -> cors.configurationSource(corsConfigurationSource()))
        .sessionManagement(session -> session
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
        );
    return http.build();
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    // 替换为你的前端域名,例如http://localhost:3000
    config.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
    config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    config.setAllowedHeaders(Collections.singletonList("*"));
    // 允许携带Cookie
    config.setAllowCredentials(true);
    
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}

前端请求配置

发起请求时需开启withCredentials,以Axios为例:

axios.get('/current', { withCredentials: true })

4. 验证效果

登录成功后,查看浏览器Cookie列表,应存在JSESSIONID。此时访问/current接口,即可从SecurityContextHolder中获取到正确的用户ID与权限。


内容的提问来源于stack exchange,提问作者hezf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:40:36