35

我已经阅读了有关 SO 的文档和所有相关问题,但 Angular 的 XSRF 机制仍然对我不起作用:我无法发出带有自动附加 X-XSRF-TOKEN 标头的 POST 请求。

我有一个带有登录表单的 Angular 6 应用程序。

它是 Symfony (PHP 7.1) 网站的一部分,当从 Symfony 提供时,Angular 应用程序页面会发送正确的 Cookie ( XSRF-TOKEN):

在此处输入图像描述

我的 app.module.ts 包含正确的模块:

// other imports...
import {HttpClientModule, HttpClientXsrfModule} from "@angular/common/http";

// ...
@NgModule({
  declarations: [
    // ...
  ],
  imports: [
    NgbModule.forRoot(),
    BrowserModule,
    // ...
    HttpClientModule,
    HttpClientXsrfModule.withOptions({
      cookieName: 'XSRF-TOKEN',
      headerName: 'X-CSRF-TOKEN'
    }),
    // other imports
  ],
  providers: [],
  entryComponents: [WarningDialog],
  bootstrap: [AppComponent]
})
export class AppModule {
}

然后,在 Service 的方法中,我发出以下 http 请求(this.http是 的一个实例HttpClient):

this.http
    .post<any>('api/login', {'_username': username, '_pass': password})
    .subscribe(/* handler here */);

发布请求从不发送 X-XSRF-TOKEN 标头。为什么?

4

8 回答 8

48

问题再次是 Angular 糟糕的文档。

事实是,只有当cookie是在服务器端使用以下选项生成时,Angular 才会添加X-XSRF-TOKEN标头:XSRF-TOKEN

  • 路径 =/
  • httpOnly = false(这是非常重要的,并且完全没有记录

此外,Angular 应用程序和被调用的 URL 必须驻留在同一台服务器上。

参考:this Angular Github issue

于 2018-05-24T14:17:47.820 回答
26

在我的团队中,问题在于我们使用的是绝对路径而不是相对路径。

所以不要使用绝对路径,例如:

this.http.post<any>("https://example.com/api/endpoint",data)

采用

this.http.post<any>("api/endpoint",data)

或使用

this.http.post<any>("//example.com/api/endpoint",data)

这是因为绝对路径被 HttpClientXsrfModule 上的 Angular 代码显式忽略(请参阅

于 2020-01-03T23:18:33.077 回答
6

稍微偏离主题,但对于其他来这里的人,我通过以下方式在后端解决了这个问题(for spring-boot

     /**
     * CORS config - used by cors() in configure() DO NOT CHANGE the METDHO NAME
     * 
     * @return
     */
    @Bean()
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Lists.newArrayList("http://localhost:4200"));
        configuration.setAllowedMethods(Lists.newArrayList("GET", "POST", "OPTIONS"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Lists.newArrayList("x-xsrf-token", "XSRF-TOKEN"));
        configuration.setMaxAge(10l);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
于 2019-02-10T17:36:37.943 回答
6

经过无数小时的努力,对我们有用的解决方案是将请求(在 Angular 中)从“ https://example.com ”更改为“//example.com”。

其他解决方案都不适合我们。

于 2019-11-04T12:36:10.217 回答
5

你应该把这个服务放在前端{ withCredentials: true }

前任:

this.http.put<class>(url, body, { withCredentials: true });
于 2019-11-29T09:24:06.390 回答
3

确保您的服务器X-CSRF-Token浏览器请求OPTIONS方法时允许标头。

例子:

Access-Control-Allow-Headers: X-CSRF-Token, Content-Type

参考:MDN 文档

于 2018-05-24T13:59:40.133 回答
2
    request = request.clone({
        withCredentials: true
      });

在 InterceptService 中,这对我有用

于 2020-01-30T15:08:23.383 回答
0

对于 Spring Boot 用户来说,下面这个花了我一段时间:

此外,Angular 应用程序和被调用的 URL 必须驻留在同一台服务器上。

我在我的本地主机上使用不同端口上的应用程序测试我的解决方案,它的工作方式就像它是同一个来源一样。

但是问题发生在我更改上下文路径之后:/api这与原点不同,这就是为什么我认为 Angular 不会将XSRF令牌添加到请求中,所以我需要添加:

final CookieCsrfTokenRepository cookieCsrfTokenRepository =  CookieCsrfTokenRepository.withHttpOnlyFalse();
    cookieCsrfTokenRepository.setCookiePath("/");

设置它们相同的原点

这是针对不同上下文路径的复杂解决方案

于 2022-01-10T10:56:58.210 回答