What is the right way to use angular2 http requests with Django CSRF protection?

后端 未结 7 735
独厮守ぢ
独厮守ぢ 2020-11-28 13:23

In Angular1 the problem can be solved by configuring $http-provider. Like:

app.config(function($httpProvider) {
  $httpProvider.defaults.xsrfCookieName = \'c         


        
相关标签:
7条回答
  • 2020-11-28 13:58

    Solution for Angular2 is not as easy as for angular1. You need:

    1. Pick out csrftoken cookie value.

    2. Add this value to request headers with name X-CSRFToken.

    I offer this snippet:

    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})
    ]);
    
    0 讨论(0)
  • 2020-11-28 13:58

    I struggled with this for a few days. The advice in this article is good, but as of August, 2017 is deprecated (https://github.com/angular/angular/pull/18906). The angular2 recommended approach is simple, but has a caveat.

    The recommend approach is to use HttpClientXsrfModule and to configure it to recognize django's default csrf protection. According to the django docs, django will send the cookie csrftoken and expect the client to return the header X-CSRFToken. In angular2, add the following to your app.module.ts

    import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http';
    
    @NgModule({
      imports: [
        HttpClientModule,
        HttpClientXsrfModule.withOptions({
          cookieName: 'csrftoken',
          headerName: 'X-CSRFToken',
        })
      ], ...
    

    The caveat is that angular2's XSRF Protection only applies to mutating requests:

    By default, an interceptor sends this cookie [header] on all mutating requests (POST, etc.) to relative URLs but not on GET/HEAD requests or on requests with an absolute URL.

    If you need to support an API that performs mutation on GET/HEAD, you will need to create your own custom interceptor. You can find an example and a discussion of the issue here.

    0 讨论(0)
  • 2020-11-28 14:01

    Victor K's answer is perfectly valid however as of angular 2.0.0-rc.2, a preferred approach would be to use CookieXSRFStrategy as below,

    bootstrap(AngularApp, [
      HTTP_PROVIDERS,
      provide(XSRFStrategy, {useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')})
    ]);
    
    0 讨论(0)
  • 2020-11-28 14:01

    For later versions of angular you cannot call functions in decorators. You have to use a factory provider:

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

    And then use the factory:

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

    Otherwise the compiler will tell you off. What I have also seen is that ng build --watch will not report this error until you kick it off again.

    0 讨论(0)
  • 2020-11-28 14:11

    Victor K had the solution, I'll just add this comment here as to what I did:

    I created the component "ExRequestOptions" as Victor K said, but I also added a method "appendHeaders" to that component:

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

    Then I had this in my main.ts:

    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})]);
    

    I'm not sure the bootstrapping had any effect, so i also did this where I would post data:

        let options = new ExRequestOptions();
        options.appendHeaders('Content-Type', 'application/json');
        return this.http.post('.....URL', JSON.stringify(registration),
             options)
    
    0 讨论(0)
  • 2020-11-28 14:14

    Currently, I solve anything with custom headers using a wrapper service around the Http Service. You can add whatever header manually and inject additional services for storing/retrieving values. This strategy also works for JWTs, for example. Have a look at the code below, I hope it helps.

    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});
      }
    }
    
    0 讨论(0)
提交回复
热议问题