Qual è il modo giusto di utilizzare le richieste http angular2 con la protezione di Django CSRF?

In Angular1 il problema può essere risolto configurando $ http-provider. Piace:

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

Qual è una buona pratica per fare lo stesso in Angular2?

In Angular2 per lavorare con le richieste http è necessario utilizzare la class Http. Ovviamente non è una buona pratica aggiungere CSRF-line ad ogni chiamata di post-funzione.

Credo che in Angular2 dovrei creare una propria class che erediti la class Http di Angular2 e ridefinire la funzione post. È l’approccio giusto o esiste un metodo più elegante?

    La risposta di Victor K è perfettamente valida tuttavia a partire da angular 2.0.0-rc.2, un approccio preferenziale sarebbe quello di usare CookieXSRFStrategy come di seguito,

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

    Ora che viene rilasciato Angular 2, il seguente sembra essere il modo corretto di farlo, utilizzando CookieXSRFStrategy .

    Ho configurato la mia applicazione per avere un modulo principale ma puoi fare lo stesso nel tuo modulo principale dell’applicazione:

     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 { }, 

    La soluzione per Angular2 non è facile come per angular1. Hai bisogno:

    1. Seleziona il valore del cookie csrftoken .

    2. Aggiungi questo valore per richiedere intestazioni con nome X-CSRFToken .

    Offro questo frammento:

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

    Per le versioni successive di angolari non è ansible chiamare le funzioni nei decoratori. Devi usare un fornitore di fabbrica:

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

    E quindi utilizzare la fabbrica:

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

    Altrimenti il ​​compilatore ti avviserà. Quello che ho anche visto è che ng build –watch non segnalerà questo errore finché non lo avvii di nuovo.

    Victor K ha avuto la soluzione, aggiungerò qui questo commento per ciò che ho fatto:

    Ho creato il componente “ExRequestOptions” come diceva Victor K, ma ho aggiunto anche un metodo “appendHeaders” a quel componente:

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

    Poi ho avuto questo nel mio 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})]); 

    Non sono sicuro che il bootstrap abbia avuto alcun effetto, quindi l’ho fatto anche dove avrei inserito i dati:

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

    Ho lottato con questo per alcuni giorni. Il consiglio in questo articolo è buono, ma a partire da agosto 2017 è deprecato ( https://github.com/angular/angular/pull/18906 ). L’approccio raccomandato da angular2 è semplice, ma ha un avvertimento.

    L’approccio consigliato è quello di utilizzare HttpClientXsrfModule e configurarlo per riconoscere la protezione csrf predefinita di django. Secondo i documenti di django, django invierà il cookie csrftoken e si aspetta che il client restituisca l’intestazione X-CSRFToken . In angular2, aggiungi quanto segue al tuo app.module.ts

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

    L’avvertenza è che la protezione XSRF di angular2 si applica solo alle richieste mutanti:

    Per impostazione predefinita, un intercettore invia questo cookie [intestazione] a tutte le richieste mutanti (POST, ecc.) Agli URL relativi ma non alle richieste GET / HEAD o alle richieste con un URL assoluto.

    Se è necessario supportare un’API che esegue la mutazione su GET / HEAD, sarà necessario creare il proprio interceptor personalizzato. Puoi trovare un esempio e una discussione del problema qui .

    Attualmente risolvo qualsiasi cosa con intestazioni personalizzate utilizzando un servizio wrapper attorno al servizio Http. È ansible aggiungere qualsiasi intestazione manualmente e iniettare servizi aggiuntivi per l’archiviazione / il recupero dei valori. Questa strategia funziona anche per le JWT, ad esempio. Dai un’occhiata al codice qui sotto, spero che aiuti.

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