在Angular1中,可以通过配置$ http-provider来解决问题。像:
app.config(function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
});
在Angular2中做同样的事情有什么好处?
在Angular2中使用http请求我们需要使用类Http。当然,对每个后期函数调用添加CSRF行并不是一个好习惯。
我想在Angular2中我应该创建自己的类来继承Angular2的Http类并重新定义后期函数。这是正确的方法还是有更优雅的方法?
答案 0 :(得分:18)
现在已经发布了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 {
},
答案 1 :(得分:13)
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})
]);
答案 2 :(得分:10)
Victor K的答案完全有效,但是从角度2.0.0-rc.2开始,首选的方法是使用CookieXSRFStrategy,如下所示,
bootstrap(AngularApp, [
HTTP_PROVIDERS,
provide(XSRFStrategy, {useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')})
]);
答案 3 :(得分:4)
对于更高版本的角度,您无法在装饰器中调用函数。您必须使用工厂提供商:
export function xsrfFactory() {
return new CookieXSRFStrategy('_csrf', 'XSRF-TOKEN');
}
然后使用工厂:
providers: [
{
provide: XSRFStrategy,
useFactory : xsrfFactory
}],
否则编译器会告诉你。 我还看到,在你再次启动之前,ng build --watch不会报告此错误。
答案 4 :(得分:2)
Victor K有解决方案,我只是在这里添加这个评论我做了什么:
我创建了组件“ExRequestOptions”,正如Victor K所说,但我还在该组件中添加了一个方法“appendHeaders”:
appendHeaders(headername: string, headervalue: string) {
this.headers.append(headername, headervalue);
}
然后我在我的主文件中有这个:
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)
答案 5 :(得分:2)
我挣扎了几天。本文中的建议很好,但截至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' s XSRF Protection仅适用于变更请求:
默认情况下,拦截器会在所有变更请求上发送此cookie [header] (POST等)到相对URL但不在GET / HEAD请求上或打开 请求使用绝对URL。
如果您需要支持在GET / HEAD上执行变异的API,则需要创建自己的自定义拦截器。您可以找到问题here的示例和讨论。
答案 6 :(得分:1)
目前,我使用围绕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});
}
}