使用带有Django CSRF保护的angular2 http请求的正确方法是什么?

时间:2015-12-28 13:56:28

标签: django csrf angular django-csrf

在Angular1中,可以通过配置$ http-provider来解决问题。像:

app.config(function($httpProvider) {
  $httpProvider.defaults.xsrfCookieName = 'csrftoken';
  $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
});

在Angular2中做同样的事情有什么好处?

在Angular2中使用http请求我们需要使用类Http。当然,对每个后期函数调用添加CSRF行并不是一个好习惯。

我想在Angular2中我应该创建自己的类来继承Angular2的Http类并重新定义后期函数。这是正确的方法还是有更优雅的方法?

7 个答案:

答案 0 :(得分:18)

现在已经发布了Angular 2,使用CookieXSRFStrategy以下似乎是正确的方法。

我已将我的应用程序配置为core module,但您可以在主应用程序模块中执行相同操作:

import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
import { CommonModule }   from '@angular/common';
import { HttpModule, XSRFStrategy, CookieXSRFStrategy } from '@angular/http';

@NgModule({
    imports: [
        CommonModule,
        HttpModule
     ],
    declarations: [ ],
    exports: [ ],
    providers: [
        {
            provide: XSRFStrategy,
            useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')
        }
    ]
})


export class CoreModule {
}, 

答案 1 :(得分:13)

Angular2的解决方案并不像angular1那么容易。 你需要:

  1. 选择csrftoken Cookie值。

  2. 将此值添加到名为X-CSRFToken的请求标头。

  3. 我提供此代码段:

    import {Injectable, provide} from 'angular2/core';
    import {BaseRequestOptions, RequestOptions} from 'angular2/http'
    
    @Injectable()
    export class ExRequestOptions extends BaseRequestOptions  {
      constructor() {
        super();
        this.headers.append('X-CSRFToken', this.getCookie('csrftoken'));
      }
    
      getCookie(name) {
        let value = "; " + document.cookie;
        let parts = value.split("; " + name + "=");
        if (parts.length == 2) 
          return parts.pop().split(";").shift();
      }
    }
    
    export var app = bootstrap(EnviromentComponent, [
      HTTP_PROVIDERS,
      provide(RequestOptions, {useClass: ExRequestOptions})
    ]);
    

答案 2 :(得分:10)

Victor K的答案完全有效,但是从角度2.0.0-rc.2开始,首选的方法是使用CookieXSRFStrategy,如下所示,

bootstrap(AngularApp, [
  HTTP_PROVIDERS,
  provide(XSRFStrategy, {useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')})
]);

答案 3 :(得分:4)

对于更高版本的角度,您无法在装饰器中调用函数。您必须使用工厂提供商:

export function xsrfFactory() {
  return new CookieXSRFStrategy('_csrf', 'XSRF-TOKEN');
}

然后使用工厂:

  providers: [
    {
      provide: XSRFStrategy,
      useFactory : xsrfFactory
  }],

否则编译器会告诉你。 我还看到,在你再次启动之前,ng build --watch不会报告此错误。

答案 4 :(得分:2)

Victor K有解决方案,我只是在这里添加这个评论我做了什么:

我创建了组件“ExRequestOptions”,正如Victor K所说,但我还在该组件中添加了一个方法“appendHeaders”:

appendHeaders(headername: string, headervalue: string) {
    this.headers.append(headername, headervalue);
}

然后我在我的主文件中有这个:

import {bootstrap}    from 'angular2/platform/browser'
import {AppComponent} from './app.component'
import {HTTP_PROVIDERS, RequestOptions} from 'angular2/http';
import 'rxjs/Rx';
import {ExRequestOptions} from './transportBoxes/exRequestOptions';
import {provide} from 'angular2/core';

bootstrap(AppComponent,[ HTTP_PROVIDERS,  
    provide(RequestOptions, {useClass: ExRequestOptions})]);

我不确定引导是否有任何影响,所以我也在这里做到了 我会发布数据:

    let options = new ExRequestOptions();
    options.appendHeaders('Content-Type', 'application/json');
    return this.http.post('.....URL', JSON.stringify(registration),
         options)

答案 5 :(得分:2)

我挣扎了几天。本文中的建议很好,但截至2017年8月已被弃用(https://github.com/angular/angular/pull/18906)。 angular2推荐的方法很简单,但有一点需要注意。

建议的方法是使用HttpClientXsrfModule并将其配置为识别django的默认csrf保护。根据django docs,django将发送cookie csrftoken并期望客户端返回标头X-CSRFToken。在angular2中,将以下内容添加到app.module.ts

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

@NgModule({
  imports: [
    HttpClientModule,
    HttpClientXsrfModule.withOptions({
      cookieName: 'csrftoken',
      headerName: 'X-CSRFToken',
    })
  ], ...

需要注意的是,angular2' s XSRF Protection仅适用于变更请求:

  

默认情况下,拦截器会在所有变更请求上发送此cookie [header]   (POST等)到相对URL但不在GET / HEAD请求上或打开   请求使用绝对URL。

如果您需要支持在GET / HEAD上执行变异的API,则需要创建自己的自定义拦截器。您可以找到问题here的示例和讨论。

答案 6 :(得分:1)

目前,我使用围绕Http服务的包装器服务解决任何带有自定义标头的问题。您可以手动添加任何标头,并注入用于存储/检索值的其他服务。例如,该策略也适用于JWT。看看下面的代码,我希望它有所帮助。

import {Injectable} from '@angular/core';
import {Http, Headers, RequestOptions} from '@angular/http';

@Injectable()
export class HttpService {
  constructor(private http: Http) {
  }

  private get xsrfToken() {
    // todo: some logic to retrieve the cookie here. we're in a service, so you can inject anything you'd like for this
    return '';
  }

  get(url) {
    return this.http.get(url, this.getRequestOptions())
      .map(result => result.json())
      .catch(error => error.json());
  }

  post(url, payload) {
    return this.http.post(url, payload, this.getRequestOptions())
      .map(result => result.json())
      .catch(error => error.json());
  }

  private getRequestOptions() {
    const headers = new Headers({'Content-Type': 'application/json', 'X-XSRF-TOKEN': this.xsrfToken});
    return new RequestOptions({headers: headers});
  }
}