使用带有 Django CSRF 保护的 angular2 http 请求的正确方法是什么?
What is the right way to use angular2 http requests with Django CSRF protection?
在Angular1中可以通过配置$http-provider来解决这个问题。喜欢:
app.config(function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
});
在 Angular2 中执行相同操作的最佳做法是什么?
在 Angular2 中处理 http 请求我们需要使用 class Http。当然,在 post-function.
的每次调用中添加 CSRF 行并不是一个好的做法。
我想在 Angular2 中我应该创建自己的 class 继承 Angular2 的 Http class 并重新定义 post 函数。是正确的做法还是有更优雅的方法?
Angular2 的解决方案不像 angular1 那样容易。
您需要:
选择 csrftoken
cookie 值。
将此值添加到名称为 X-CSRFToken
的请求 headers。
我提供这个片段:
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})
]);
Victor 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})]);
我不确定引导程序是否有任何效果,所以我也是这样做的
我会 post 数据:
let options = new ExRequestOptions();
options.appendHeaders('Content-Type', 'application/json');
return this.http.post('.....URL', JSON.stringify(registration),
options)
Victor K 的回答完全有效,但是从 angular 2.0.0-rc.2 开始,首选方法是使用 CookieXSRFStrategy,如下所示,
bootstrap(AngularApp, [
HTTP_PROVIDERS,
provide(XSRFStrategy, {useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')})
]);
现在 Angular 2 已发布,以下似乎是正确的方法,使用 CookieXSRFStrategy
。
我已将我的应用程序配置为具有 core module,但您可以在主应用程序模块中执行相同的操作:
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 {
},
目前,我使用围绕 Http 服务的包装器服务解决任何自定义 headers 问题。您可以手动添加任何 header 并为 storing/retrieving 值注入额外的服务。例如,此策略也适用于 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});
}
}
对于 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 and to configure it to recognize django's default csrf protection. According to the django docs,django 将发送 cookie csrftoken
并期望客户端 return header 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 仅适用于变异请求:
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.
如果您需要支持对 GET/HEAD 执行突变的 API,您将需要创建自己的自定义拦截器。您可以找到问题的示例和讨论 here。
在Angular1中可以通过配置$http-provider来解决这个问题。喜欢:
app.config(function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
});
在 Angular2 中执行相同操作的最佳做法是什么?
在 Angular2 中处理 http 请求我们需要使用 class Http。当然,在 post-function.
的每次调用中添加 CSRF 行并不是一个好的做法。我想在 Angular2 中我应该创建自己的 class 继承 Angular2 的 Http class 并重新定义 post 函数。是正确的做法还是有更优雅的方法?
Angular2 的解决方案不像 angular1 那样容易。 您需要:
选择
csrftoken
cookie 值。将此值添加到名称为
X-CSRFToken
的请求 headers。
我提供这个片段:
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})
]);
Victor 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})]);
我不确定引导程序是否有任何效果,所以我也是这样做的 我会 post 数据:
let options = new ExRequestOptions();
options.appendHeaders('Content-Type', 'application/json');
return this.http.post('.....URL', JSON.stringify(registration),
options)
Victor K 的回答完全有效,但是从 angular 2.0.0-rc.2 开始,首选方法是使用 CookieXSRFStrategy,如下所示,
bootstrap(AngularApp, [
HTTP_PROVIDERS,
provide(XSRFStrategy, {useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')})
]);
现在 Angular 2 已发布,以下似乎是正确的方法,使用 CookieXSRFStrategy
。
我已将我的应用程序配置为具有 core module,但您可以在主应用程序模块中执行相同的操作:
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 {
},
目前,我使用围绕 Http 服务的包装器服务解决任何自定义 headers 问题。您可以手动添加任何 header 并为 storing/retrieving 值注入额外的服务。例如,此策略也适用于 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});
}
}
对于 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 and to configure it to recognize django's default csrf protection. According to the django docs,django 将发送 cookie csrftoken
并期望客户端 return header 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 仅适用于变异请求:
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.
如果您需要支持对 GET/HEAD 执行突变的 API,您将需要创建自己的自定义拦截器。您可以找到问题的示例和讨论 here。