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

本地开发React/Springboot无法传递fusionauth的app.at Cookie至后端

解决FusionAuth登录后app.at Cookie无法传递到SpringBoot后端的问题

核心问题分析

  1. FusionAuth生成的app.at Cookie默认开启httpOnly属性,前端JS无法直接读取,因此无法手动将Token放入请求头的Authorization字段。
  2. Spring Security的BearerTokenAuthenticationFilter默认仅从请求头Authorization: Bearer <token>或请求参数中提取Token,不会自动读取Cookie中的app.at。
  3. 前端Axios配置中错误设置了Access-Control-Allow-Origin: *,当withCredentials: true时,该值不能为通配符,会导致Cookie无法被携带。

分步解决方案

1. 修正前端Axios配置

删除前端Axios中无效的Access-Control-Allow-Origin响应头(该头由后端返回,前端设置无意义),确保withCredentials: true正确生效:

const api = axios.create({
  withCredentials: true,
  baseURL: 'http://localhost:8080/api',
  headers: {
    'Content-Type': 'application/json',
  },
});

2. 让SpringBoot从Cookie中提取app.at Token

两种方案选其一即可:

方案一:自定义过滤器将Cookie转成Authorization头

编写过滤器读取app.at Cookie的值,注入到请求头的Authorization字段中,让BearerTokenAuthenticationFilter能识别:

@Component
public class FusionAuthCookieToHeaderFilter 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 ("app.at".equals(cookie.getName())) {
                    String token = cookie.getValue();
                    // 包装请求,添加Authorization头
                    request = new HttpServletRequestWrapper(request) {
                        @Override
                        public String getHeader(String name) {
                            if ("Authorization".equals(name)) {
                                return "Bearer " + token;
                            }
                            return super.getHeader(name);
                        }

                        @Override
                        public Enumeration<String> getHeaders(String name) {
                            if ("Authorization".equals(name)) {
                                return Collections.enumeration(Collections.singletonList("Bearer " + token));
                            }
                            return super.getHeaders(name);
                        }
                    };
                    break;
                }
            }
        }
        filterChain.doFilter(request, response);
    }
}

然后在Security配置中,将该过滤器添加到BearerTokenAuthenticationFilter之前:

@Bean
public SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http, FusionAuthCookieToHeaderFilter cookieFilter) throws Exception {
    http.cors(corsConfig -> corsConfig.configurationSource(corsConfigurationSource()))
        // 自定义过滤器放在BearerToken过滤器之前
        .addFilterBefore(cookieFilter, BearerTokenAuthenticationFilter.class)
        .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())))
        // 其他安全配置...
        .authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
    return http.build();
}
方案二:自定义BearerTokenResolver直接从Cookie取Token

通过配置Spring Security的BearerTokenResolver,让它优先从Cookie中读取app.at:

@Bean
public SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http) throws Exception {
    http.cors(corsConfig -> corsConfig.configurationSource(corsConfigurationSource()))
        .oauth2ResourceServer(oauth2 -> oauth2
            .bearerTokenResolver(request -> {
                // 先从Cookie读取app.at
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        if ("app.at".equals(cookie.getName())) {
                            return cookie.getValue();
                        }
                    }
                }
                //  fallback到默认的解析逻辑(请求头/参数)
                return new DefaultBearerTokenResolver().resolve(request);
            })
            .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
        )
        .authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
    return http.build();
}

3. 检查FusionAuth的Cookie配置

登录FusionAdmin后台,进入对应应用的Security配置页,调整Cookie设置:

  • Domain:本地开发可留空或设置为localhost
  • Path:设为/
  • SameSite:设为Lax(本地http环境),若为https可设为None(需开启Secure)
  • Secure:本地http环境关闭,https环境开启

确保这些配置正确,否则浏览器可能不会在跨域请求中携带app.at Cookie。

4. 验证请求流程

  1. 登录FusionAuth后,打开浏览器开发者工具的Application面板,确认app.at Cookie存在且属性符合上述配置。
  2. 前端发起请求时,查看Network面板的请求头,确认Cookie: app.at=<token>已被携带。
  3. 后端调试时,确认BearerTokenAuthenticationFilter已能获取到Token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 07:31:14