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

ReactJS客户端如何存储Spring Security OAuth2 JWT令牌?能否配置授权服务器返回HttpOnly Cookie?

React客户端存储Spring Security授权服务器JWT令牌的最佳方案

一、主流令牌存储方案对比

  • HttpOnly Cookie:安全性最高,能规避XSS攻击(JS无法读取Cookie内容),但需处理跨域、CSRF防护等问题,是生产环境的首选。
  • LocalStorage/SessionStorage:前端读取便捷,但极易被XSS攻击窃取令牌,不适合存储敏感的访问令牌。
  • 内存存储:页面刷新后令牌丢失,仅适合短期临时会话,用户体验较差。

二、配置Spring Security授权服务器返回HttpOnly Cookie令牌

Spring Security授权服务器(5.7及以上版本)支持直接将JWT令牌存入HttpOnly Cookie,无需通过自定义端点破坏原有OAuth2流程,具体配置如下:

  1. 自定义令牌处理器,将生成的JWT写入HttpOnly Cookie:
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtTokenCustomizer() {
    return context -> {
        HttpServletResponse response = context.getExchange().getResponse();
        String accessToken = context.getToken().getTokenValue();
        
        Cookie accessTokenCookie = new Cookie("access_token", accessToken);
        accessTokenCookie.setHttpOnly(true);
        accessTokenCookie.setSecure(true); // 生产环境启用HTTPS时必须开启
        accessTokenCookie.setPath("/");
        accessTokenCookie.setMaxAge(3600); // 有效期需与JWT自身过期时间保持一致
        
        response.addCookie(accessTokenCookie);
    };
}
  1. 配置CORS允许携带Cookie:
@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(List.of("http://你的React域名"));
    config.setAllowedMethods(List.of("GET", "POST", "OPTIONS"));
    config.setAllowedHeaders(List.of("*"));
    config.setAllowCredentials(true);
    
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}
  1. React客户端请求时需携带凭证:
fetch('http://资源服务器地址/api/接口', {
  credentials: 'include'
})

三、自定义端点方案的问题修复

若你之前尝试的自定义端点破坏了授权流程,核心原因是未同步令牌状态(如过期时间、刷新令牌关联)。若坚持使用该方案,需注意:

  • 自定义端点需接收授权服务器返回的完整令牌数据,将访问令牌存入HttpOnly Cookie,刷新令牌建议也存入HttpOnly Cookie(避免前端读取)
  • 资源服务器需配置Cookie令牌解析逻辑,示例如下:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
        .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())))
        .addFilterBefore(new CookieTokenExtractorFilter(), UsernamePasswordAuthenticationFilter.class);
    return http.build();
}

// 自定义过滤器:从Cookie中提取access_token并构建认证对象
public class CookieTokenExtractorFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("access_token".equals(cookie.getName())) {
                    String token = cookie.getValue();
                    // 解析JWT并设置认证信息到SecurityContext
                    Jwt jwt = JwtDecoderFactory.create().decode(token);
                    Authentication auth = new JwtAuthenticationToken(jwt, null);
                    SecurityContextHolder.getContext().setAuthentication(auth);
                    break;
                }
            }
        }
        filterChain.doFilter(request, response);
    }
}

四、关键注意事项

  • CSRF防护:使用HttpOnly Cookie时必须开启Spring Security的CSRF防护,React客户端需获取CSRF令牌并在请求时放入X-XSRF-TOKEN Header。
  • 令牌刷新:刷新流程建议由后端处理,前端仅调用刷新接口,无需接触刷新令牌。
  • 跨域一致性:授权服务器、资源服务器、React客户端的CORS配置必须统一,确保凭证能正常传递。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:11:01