Angular6 不在http请求中添加X-XSRF-TOKENheader

Angular 6 does not add X-XSRF-TOKEN header to http request

我已经阅读了 the docs 以及关于 SO 的所有相关问题,但是 Angular 的 XSRF 机制仍然不适合我:我决不能制作 POST 请求自动附加 X-XSRF-TOKEN header。

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

它是 Symfony (PHP 7.1) 网站的一部分,并且 Angular 应用程序页面在从 Symfony 提供时发送正确的 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 {
}

然后,在服务的方法中,我发出了以下 http 请求(this.httpHttpClient 的一个实例):

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

post 请求从不发送 X-XSRF-TOKEN header。为什么?

确保您的服务器允许 X-CSRF-Token headers 在 browser requests OPTIONS method.

时启用

示例:

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

参考:MDN Docs

问题又是 Angular 的糟糕文档。

事实是,Angular 将添加 X-XSRF-TOKEN header 仅当 生成 XSRF-TOKEN cookie server-side 具有以下选项:

  • 路径=/
  • httpOnly = false(这很重要,完全未记录

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

参考:this Angular Github issue

稍微偏离主题,但对于来到这里的其他人,我通过以下方式在后端解决了这个问题(对于 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;
    }

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

None 其他解决方案对我们有用。

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

例如:

this.http.put<class>(url, body, { withCredentials: true });

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

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

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 (see)

上的 Angular 代码显式忽略
    request = request.clone({
        withCredentials: true
      });

在 InterceptService 中,这对我有用

对于 Spring 引导用户,下面的内容花了我一段时间:

Besides, the Angular app and the URL being called must reside on the same server.

我在我的本地主机上用不同端口上的应用程序测试我的解决方案,它的工作原理就像是同源的。

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

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

设置同源

Here is complex solution for diffrent context-path