2015-12-28 1 views
17

Dans Angular1, le problème peut être résolu en configurant $ http-provider. Comme:Quelle est la bonne façon d'utiliser les requêtes http angular2 avec la protection Django CSRF?

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

Quelle est la bonne pratique pour faire la même chose dans Angular2?

En Angular2 pour travailler avec les requêtes http, nous devons utiliser la classe Http. Bien sûr, ce n'est pas une bonne pratique d'ajouter CSRF-line à chaque appel de post-fonction.

Je suppose que dans Angular2 je devrais créer ma propre classe qui hérite de la classe Http de Angular2 et redéfinir la post-fonction. Est-ce la bonne approche ou existe-t-il une méthode plus élégante?

+0

Oui, nous pouvons un service global et vous pouvez écrire n'importe quoi tout ce que vous voulez tout au long de votre application. puis fournir ce service global dans le fichier bootstrap. Je pense que cela vous donne un indice –

+0

Maintenant que la version 2.0 a été officiellement publiée, les réponses précédentes ne semblent plus fonctionner. S'il vous plaît voir ma réponse ci-dessous sur la façon d'utiliser CookieXSRFStrategy. – David

Répondre

10

réponse de Victor K est parfaitement valable cependant que de angulaire 2.0.0-rc.2, une approche préférée serait d'utiliser CookieXSRFStrategy comme ci-dessous,

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

depuis fournir est obsolète, je suppose que la nouvelle façon devrait être de remplacer la ligne fournie avec '{provide: XSRFStrategy, useValue: new CookieXSRFStrategy ('csrftoken', 'X-CSRFToken')}' – maxbellec

+0

Cette solution ne fonctionne pas dans la version finale d'Angular 2. Veuillez voir ma réponse ci-dessous. – David

13

La solution pour Angular2 n'est pas aussi simple que pour Angular1. Vous avez besoin:

  1. choisir la valeur csrftoken cookie.

  2. Ajoutez cette valeur aux en-têtes avec le nom X-CSRFToken.

Je propose cet extrait:

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

Je suppose que vous devriez accepter votre réponse. –

+0

Victor, avez-vous besoin de faire quelque chose de spécial pour obtenir le cookie du serveur Django? Quand je vérifie les cookies, le csrftoken n'existe pas. –

+0

Oui, votre fonction d'affichage doit être décorée avec @csrf_protect ou la classe CsrfViewMiddleware doit être ajoutée à MIDDLEWARE_CLASSES dans le fichier de paramètres. Détails ici https://docs.djangoproject.com/fr/1.9/ref/csrf/#module-django.views.decorators.csrf –

2

Victor K avait la solution, je vais juste ajouter ce commentaire ici à ce que je faisais:

J'ai créé le composant "ExRequestOptions" comme Victor K dit, mais j'ai aussi ajouté une méthode « appendHeaders » à ce composant:

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

J'avais dans mes 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})]); 

Je ne suis pas sûr que le bootstrapping avait aucun effet, donc je l'ai fait aussi ce où je posterais des données:

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

Maintenant que Angul ar 2 est publié ce qui suit semble être la bonne façon de le faire, en utilisant CookieXSRFStrategy.

J'ai configuré ma demande d'avoir un core module mais vous pouvez faire la même chose dans votre module principal d'application à la place:

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

Salut lors de la première exécution J'ai reçu cette erreur: 'ERROR in Error a rencontré une résolution statique des valeurs de symboles. Appelant la fonction 'CookieXSRFStrategy', les appels de fonction ne sont pas pris en charge. Envisager de remplacer t la fonction ou lambda par une référence à une fonction exportée ». Mais quand en frappant sauve le le cli construit encore mais maintenant sans erreur. –

+1

@ ShiftN'Tab vous pouvez remplacer 'new CookieXSRFStrategy ('csrftoken', 'X-CSRFToken')' avec une fonction qui retourne cette ligne. Cela devrait le résoudre. – callback

1

Actuellement, je résous quoi que ce soit avec les en-têtes personnalisés à l'aide d'un service d'emballage autour du Service Http . Vous pouvez ajouter n'importe quel en-tête manuellement et injecter des services supplémentaires pour stocker/récupérer des valeurs. Cette stratégie fonctionne également pour les JWT, par exemple. Jetez un oeil sur le code ci-dessous, j'espère que cela aide.

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

Pour les versions ultérieures d'angular, vous ne pouvez pas appeler des fonctions dans les décorateurs.Vous devez utiliser un fournisseur d'usine:

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

Et puis utilisez l'usine:

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

Sinon, le compilateur vous quereller. Ce que j'ai également vu, c'est que ng build --watch ne signalera pas cette erreur tant que vous ne l'aurez pas relancée.