Angular1では、$ http-providerを設定することで問題を解決できます。お気に入り:
app.config(function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
});
Angular2で同じことをするための良い習慣は何ですか?
Angular2でhttpリクエストを処理するには、Httpクラスを使用する必要があります。もちろん、ポスト関数の各呼び出しにCSRF行を追加することはお勧めできません。
Angular2では、Angular2のHttpクラスを継承する独自のクラスを作成し、ポスト関数を再定義する必要があると思います。それは正しいアプローチですか、それともよりエレガントな方法ですか?
Victor Kの回答は完全に有効ですが、angular 2.0.0-rc.2の時点で、以下のようにCookieXSRFStrategyを使用することをお勧めします。
bootstrap(AngularApp, [
HTTP_PROVIDERS,
provide(XSRFStrategy, {useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')})
]);
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 {
},
Angular2のソリューションは、angular1ほど簡単ではありません。必要なもの:
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})
]);
angularの新しいバージョンでは、デコレータで関数を呼び出すことはできません。ファクトリプロバイダを使用する必要があります。
export function xsrfFactory() {
return new CookieXSRFStrategy('_csrf', 'XSRF-TOKEN');
}
次に、ファクトリを使用します。
providers: [
{
provide: XSRFStrategy,
useFactory : xsrfFactory
}],
それ以外の場合は、コンパイラが教えてくれます。また、ng build --watchは、もう一度開始するまでこのエラーを報告しないこともわかりました。
私はこれに数日間苦労しました。この記事のアドバイスは良いですが、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の XSRF Protection が変更リクエストにのみ適用されるということです。
デフォルトでは、インターセプターはこのCookie [ヘッダー]をすべての変更リクエスト(POSTなど)で相対URLに送信しますが、GET/HEADリクエストや絶対URLを含むリクエストでは送信しません。
GET/HEADでミューテーションを実行するAPIをサポートする必要がある場合は、独自のカスタムインターセプターを作成する必要があります。あなたは問題の例と議論を見つけることができます ここ 。
ビクターKが解決策を持っているので、私がしたことに関してこのコメントをここに追加します:
Victor Kが言ったように、「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)
現在、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});
}
}