Каков правильный способ использования angular2 http-запросов с защитой 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 и переопределяет постфункцию. Это правильный подход или есть более элегантный метод?
Ответы
Ответ 1
Ответ Victor K совершенно справедлив, однако, как и для angular 2.0.0-rc.2, предпочтительным подходом было бы использовать CookieXSRFStrategy, как показано ниже,
bootstrap(AngularApp, [
HTTP_PROVIDERS,
provide(XSRFStrategy, {useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')})
]);
Ответ 2
Теперь, когда освобождается Angular 2, кажется, что это правильный способ, используя CookieXSRFStrategy
.
Я настроил мое приложение на основной модуль, но вы можете сделать то же самое в своем основном прикладном модуле:
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 {
},
Ответ 3
Решение для Angular2 не так просто, как для углового 1.
Вам нужно:
-
Выберите значение csrftoken
cookie.
-
Добавьте это значение, чтобы запросить заголовки с именем X-CSRFToken
.
Я предлагаю этот фрагмент:
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})
]);
Ответ 4
Для более поздних версий angular вы не можете вызывать функции в декораторах. Вы должны использовать поставщика factory:
export function xsrfFactory() {
return new CookieXSRFStrategy('_csrf', 'XSRF-TOKEN');
}
И затем используйте factory:
providers: [
{
provide: XSRFStrategy,
useFactory : xsrfFactory
}],
В противном случае компилятор скажет вам.
То, что я также видел, это то, что ng build -watch не сообщит об этой ошибке, пока вы не начнете ее снова.
Ответ 5
У Виктора К было решение, я просто добавлю здесь этот комментарий к тому, что я сделал:
Я создал компонент "ExRequestOptions", как сказал Виктор К, но я также добавил метод "appendHeaders" к этому компоненту:
appendHeaders(headername: string, headervalue: string) {
this.headers.append(headername, headervalue);
}
Тогда у меня было это в моем 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})]);
Я не уверен, что начальная загрузка имела какой-то эффект, поэтому я также сделал это,
Я бы опубликовал данные:
let options = new ExRequestOptions();
options.appendHeaders('Content-Type', 'application/json');
return this.http.post('.....URL', JSON.stringify(registration),
options)
Ответ 6
В настоящее время я решаю что угодно с пользовательскими заголовками, используя сервис-обертку вокруг службы 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});
}
}