在 Django CSRF 保护中使用 angular2 http 请求的正确方法是啥?
Posted
技术标签:
【中文标题】在 Django CSRF 保护中使用 angular2 http 请求的正确方法是啥?【英文标题】:What is the right way to use angular2 http requests with Django CSRF protection?在 Django CSRF 保护中使用 angular2 http 请求的正确方法是什么? 【发布时间】:2016-04-02 09:11:15 【问题描述】:在 Angular1 中,可以通过配置 $http-provider 来解决这个问题。喜欢:
app.config(function($httpProvider)
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
);
在 Angular2 中做同样的事情有什么好的做法?
在 Angular2 中,要处理 http 请求,我们需要使用类 Http。当然,将 CSRF-line 添加到 post-function 的每个调用中并不是一个好习惯。
我想在 Angular2 中我应该创建自己的类来继承 Angular2 的 Http 类并重新定义 post 函数。这是正确的方法还是有更优雅的方法?
【问题讨论】:
是的,我们可以提供一项全球服务,您可以在整个应用程序中编写任何您想要的内容。然后将该全局服务提供到引导文件中。我认为这会给你一个提示 现在 2.0 版已经正式发布,以前的答案似乎不再有效。请参阅下面关于如何使用 CookieXSRFStrategy 的回答。 【参考方案1】:Angular2 的解决方案不像 angular1 那样简单。 你需要:
挑选csrftoken
cookie 值。
将此值添加到名称为 X-CSRFToken
的请求标头中。
我提供这个 sn-p:
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,你需要做一些特别的事情来从 Django 服务器获取 cookie 吗?当我检查 cookie 时,csrftoken 不存在。 是的,您的视图函数必须使用@csrf_protect 进行修饰,或者必须将 CsrfViewMiddleware 类添加到设置文件中的 MIDDLEWARE_CLASSES 中。详情看这里docs.djangoproject.com/en/1.9/ref/csrf/… 对于 java spring 开发者 X-CSRFToken 将是 X-CSRF ,这是一些资源spring.io/guides/tutorials/spring-security-and-angular-js 我认为现在 2.0 版本已经发布了。请参阅我的替代答案,了解适用于 2.0 的解决方案。 为什么我们需要自己获取 cookie,当文档说它可以使用 httpclient 开箱即用时(问题是,它不适合我)【参考方案2】: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)]);
我不确定引导有什么效果,所以我也在哪里做 我会发布数据:
let options = new ExRequestOptions();
options.appendHeaders('Content-Type', 'application/json');
return this.http.post('.....URL', JSON.stringify(registration),
options)
【讨论】:
【参考方案3】:Victor K 的回答完全有效,但是从 angular 2.0.0-rc.2 开始,首选方法是使用 CookieXSRFStrategy,如下所示,
bootstrap(AngularApp, [
HTTP_PROVIDERS,
provide(XSRFStrategy, useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken'))
]);
【讨论】:
由于 provide 已被弃用,我想新的方法应该是用provide:XSRFStrategy, useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')
替换 provide 行
此解决方案在 Angular 2 的发布版本中不起作用。请在下面查看我的答案。【参考方案4】:
现在 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
,
【讨论】:
您好,在第一次运行构建时我收到了这个错误:ERROR in Error encountered resolving symbol values statically. Calling function 'CookieXSRFStrategy', function calls are not supported. Consider replacing t he function or lambda with a reference to an exported function
。但是,当点击保存时,cli 再次构建,但现在没有错误。
@ShiftN'Tab 您可以将new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')
替换为返回该行的函数。那应该可以解决它。【参考方案5】:
目前,我使用围绕 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);
【讨论】:
【参考方案6】:对于更高版本的 Angular,您不能在装饰器中调用函数。您必须使用工厂供应商:
export function xsrfFactory()
return new CookieXSRFStrategy('_csrf', 'XSRF-TOKEN');
然后使用工厂:
providers: [
provide: XSRFStrategy,
useFactory : xsrfFactory
],
否则编译器会告诉你。 我还看到 ng build --watch 不会报告这个错误,直到你再次启动它。
【讨论】:
【参考方案7】:我为此苦苦挣扎了几天。本文中的建议很好,但截至 2017 年 8 月已弃用 (https://github.com/angular/angular/pull/18906)。 angular2 推荐的方法很简单,但有一个警告。
推荐的方法是使用HttpClientXsrfModule 并将其配置为识别django 的默认csrf 保护。根据djangodocs,django将发送cookiecsrftoken
并期望客户端返回标头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 [header] (POST 等)到相对 URL,但不是在 GET/HEAD 请求上或 带有绝对 URL 的请求。
如果您需要支持在 GET/HEAD 上执行突变的 API,则需要创建自己的自定义拦截器。你可以在here找到一个例子和一个问题的讨论。
【讨论】:
以上是关于在 Django CSRF 保护中使用 angular2 http 请求的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Django网络安全跨站点请求伪造保护,CSRF如何正确使用
在 Django CSRF 保护中使用 angular2 http 请求的正确方法是啥?