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

Spring Cloud Gateway后Angular应用POST请求CSRF令牌无效问题

问题:Spring Cloud Gateway 部署Angular应用时POST请求CSRF验证失败

我正尝试通过Spring Cloud Gateway部署Angular应用,GET请求正常,但向资源服务发送POST请求时,因Invalid CSRF token报错返回403 Forbidden,推测是配置问题但未定位到,官方文档对该场景帮助有限。

当前现象

POST请求返回403 Forbidden,错误信息如下:

error: "Invalid CSRF Token"
message: "Http failure response for http://gateway:8000/api/post: 403 Forbidden"
name: "HttpErrorResponse"
ok: false
status: 403
statusText: "Forbidden"
url: "http://gateway:8000/api/post"

期望效果

不关闭Spring Security的CSRF防护,POST请求可正常执行。

现有配置

网关Spring Security配置

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) throws Exception {

        return http
                .authorizeExchange(exchange -> exchange
                        .pathMatchers("/**").permitAll()
                        .anyExchange().authenticated())
                .csrf(csrf -> csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
                .build();
    }
}

网关自定义WebFilter

@Component
@Configuration
public class CsrfCookieWebFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String key = CsrfToken.class.getName();
        Mono<CsrfToken> csrfToken = null != exchange.getAttribute(key) ? exchange.getAttribute(key) : Mono.empty();
        return csrfToken.doOnSuccess(token -> {
            ResponseCookie cookie = ResponseCookie.from("XSRF-TOKEN", token.getToken())
                    .maxAge(Duration.ofHours(1))
                    .httpOnly(false)
                    .path("/")
                    .sameSite(Cookie.SameSite.LAX.attributeValue())
                    .build();
            exchange.getResponse().getCookies().add("XSRF-TOKEN", cookie);
        }).then(chain.filter(exchange));
    }
}

Angular配置

Angular应用的AppModule已导入HttpClientXsrfModule。


解决方案

问题根源

  1. Spring Cloud Gateway的CookieServerCsrfTokenRepository默认生成的CSRF Cookie名与AngularHttpClientXsrfModule默认读取的Cookie名不匹配,导致Angular无法获取有效令牌
  2. 自定义CsrfCookieWebFilter逻辑存在漏洞:当请求中无CsrfToken属性时,不会生成并返回XSRF-TOKEN Cookie,Angular拿不到令牌无法携带到请求头
  3. 网关与Angular的CSRF令牌传递、验证规则未对齐

修复步骤

1. 调整Spring Security CSRF配置,对齐Angular规则

移除自定义WebFilter,直接通过CookieServerCsrfTokenRepository显式配置与Angular匹配的Cookie和请求头名称:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) throws Exception {
        CookieServerCsrfTokenRepository csrfTokenRepository = CookieServerCsrfTokenRepository.withHttpOnlyFalse();
        // 匹配Angular默认的Cookie名称
        csrfTokenRepository.setCookieName("XSRF-TOKEN");
        // 匹配Angular默认的请求头名称
        csrfTokenRepository.setHeaderName("X-XSRF-TOKEN");

        return http
                .authorizeExchange(exchange -> exchange
                        .pathMatchers("/**").permitAll()
                        .anyExchange().authenticated())
                .csrf(csrf -> csrf.csrfTokenRepository(csrfTokenRepository))
                .build();
    }
}

2. 删除自定义CsrfCookieWebFilter

CookieServerCsrfTokenRepository已自动处理CSRF令牌的Cookie生成与传递,自定义过滤器会导致逻辑冲突或重复操作。

3. 确认Angular HttpClientXsrfModule配置

默认配置已与上述网关配置对齐,若需显式声明可在AppModule中添加:

import { HttpClientXsrfModule } from '@angular/common/http';

@NgModule({
  imports: [
    HttpClientXsrfModule.withOptions({
      cookieName: 'XSRF-TOKEN',
      headerName: 'X-XSRF-TOKEN',
    }),
    // 其他模块
  ],
})
export class AppModule { }

4. 跨域场景补充配置(若Angular与网关不同域)

如果存在跨域,需在网关添加CORS配置,允许携带凭证和自定义请求头:

@Bean
CorsWebFilter corsWebFilter() {
    CorsConfiguration corsConfig = new CorsConfiguration();
    corsConfig.setAllowedOrigins(Arrays.asList("http://你的Angular域名"));
    corsConfig.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
    corsConfig.setAllowedHeaders(Arrays.asList("*"));
    corsConfig.setAllowCredentials(true);

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", corsConfig);

    return new CorsWebFilter(source);
}

5. 验证流程

  • 发送GET请求时,浏览器应收到XSRF-TOKEN Cookie
  • 发送POST请求时,Angular自动在请求头中携带X-XSRF-TOKEN,值与Cookie一致
  • 网关Spring Security验证头中令牌与服务器端存储的令牌匹配,通过验证

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 03:55:16