在 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 请求的正确方法是啥?

django-allauth 移动客户端 csrf 保护

Django navigator.sendbeacon csrf 保护

Django 的 CSRF 保护机制

Django:POST 表单需要 CSRF? GET 没有?