我正在试验通过SpringCloudGateway提供Angular应用程序的可能性。
对于GET请求,一切都很正常,但是当我试图通过网关向资源服务发送POST请求时,请求由于“无效的CSRF令牌”而失败。
这可能是因为一些错误的配置,但我不能找到它。而且,在线文档的Spring Web关和Angular 是不是很有用的这个特定的场景。
如果您想复制此行为,下面是具有当前配置的存储库:github repo .
当前行为:来自Angular的POST请求因“无效CSRF令牌”而失败:
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"
预期行为:POST请求成功执行,未禁用spring security中的csrf。
这是我对网关的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 应用程序AppModule包含HttpClientXsrfModule的导入。
1条答案
按热度按时间frebpwbc1#
简短回答:RTFM并仔细检查您导入的
CsrfToken
(有一个用于WebMVC,另一个与另一个用于WebFlux的包不同)。此外,与Angular应用程序一样,再次检查
X-XSRF-TOKEN
标头的位置是否正确(如果请求URI是绝对的,Angular不会设置此标头:使用this.httpClient.post('/api/post', {}, {observe: 'response'})
而不是this.httpClient.post('http://gateway:8000/api/post', {}, {observe: 'response'})
,这也需要通过网关为Angular应用程序提供服务)设置CSRF cookie
从Sping Boot 3(spring-security 6)开始,必须提供一个过滤器来将CSRF cookie添加到响应中,
Cookie(Server)CsrfTokenRepository
已经不够了。这里针对servlet记录了这一点,那里针对React式应用程序记录了这一点(第二个是配置
spring-cloud-gateway
时要参考的)。本文档包含每种情况下要复制/粘贴的确切配置。另外,根据应用程序的性质导入正确的
CsrfToken
时要非常小心,否则标记将为空:request / exchange属性的名称为CsrfToken.class.getName()
,您可以从org.springframework.security.web.csrf
或org.springframework.security.web.server.csrf
导入该属性,而不会出现任何编译错误(第一个用于servlet,第二个用于webflux)。CSRF cookie不是由我的网关示例设置的,直到我意识到我已经在我的WebFilter
=〉中导入了CsrfCookie
的servlet版本CSRF内标识值未解析。正确验证CSRF令牌
如文档中所述,应将
Xor(Server)CsrfTokenRequestAttributeHandler
的handle
方法用作csrf请求处理程序(仅限handle
方法,而非完整的Xor(Server)CsrfTokenRequestAttributeHandler
示例)spring-cloud-gateway
的工作配置在
SecurityWebFilterChain
中: