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

Spring Cloud Gateway调用微服务时遭遇403 Forbidden及CSRF令牌缺失问题

解决Spring Cloud Gateway转发POST请求时的CSRF 403错误

嗨,我来帮你搞定这个403的问题!你遇到的An expected CSRF token cannot be found错误,本质原因是Spring Cloud Gateway默认会自动引入Spring Security依赖并启用CSRF防护机制——哪怕你自己没手动配置任何Spring Security功能,网关的自动配置也会帮你开启这个校验。而你的MailService没加Spring Security,所以直接调用8001端口没问题,但通过网关8000转发时就触发了CSRF校验,导致403。

下面给你两种解决方案,按需选择:

方案一:直接禁用网关的CSRF防护(简单快捷,适合不需要CSRF防护的场景)

如果你的应用是内部服务调用、开发环境,或者前端和网关已经是同源且不需要额外CSRF防护,可以直接在网关的配置文件里关闭CSRF校验:

YAML格式(application.yml)

spring:
  security:
    csrf:
      enabled: false

Properties格式(application.properties)

spring.security.csrf.enabled=false

重启网关后,再用Angular调用应该就能正常转发了。

方案二:配置CSRF令牌传递(适合需要保留CSRF防护的生产环境)

如果需要保留CSRF防护,得让网关和Angular的CSRF令牌机制兼容——Angular默认会从Cookie中读取XSRF-TOKEN,然后在POST请求时带上X-XSRF-TOKEN请求头,所以我们需要让网关正确处理这个流程:

  1. 添加网关的Spring Security配置类
    创建一个配置类,配置CSRF令牌的存储方式为Cookie,并且允许前端读取这个Cookie:
package com.smdev.gatewayservice.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.csrf.CookieServerCsrfTokenRepository;

@Configuration
@EnableWebFluxSecurity
public class GatewaySecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
            .csrf(csrf -> csrf
                // 配置CSRF令牌存储到Cookie,并且允许前端读取(HttpOnly=false)
                .csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
            );
        return http.build();
    }
}
  1. 确保网关路由保留必要的请求头和Cookie
    在你的RouteLocator配置中,确保不会过滤掉CSRF相关的请求头和Cookie,可以添加preserveHostHeader()或者显式保留头的配置:
@Bean
public RouteLocator getRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
    return routeLocatorBuilder.routes()
            .route(p -> p
                    .path("/api/mail/**")
                    .filters(f -> f
                            .dedupeResponseHeader("Access-Control-Allow-Origin", "RETAIN_UNIQUE")
                            .preserveHostHeader() // 保留主机头,确保请求信息完整
                    )
                    .uri("http://localhost:8001"))
            .build();
}

这样配置后,Angular会自动从网关的Cookie中获取XSRF-TOKEN,并在POST请求时带上X-XSRF-TOKEN头,网关的CSRF校验就能通过,正常转发请求到MailService了。

补充说明

为什么直接调用8001端口没问题?因为你的MailService没有引入Spring Security依赖,所以不存在CSRF校验逻辑;而Spring Cloud Gateway的starter默认包含了Spring Security的相关依赖,自动开启了CSRF防护,这才是问题的核心。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 16:52:41