如何作为API向Django检索CSRF令牌/从Django提供CSRF令牌 [英] How to retrieve/provide a CSRF token to/from Django as an API

查看:126
本文介绍了如何作为API向Django检索CSRF令牌/从Django提供CSRF令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在一个使用Django REST框架作为后端的项目(例如,在api.somecompany.com处,但是有一个React.js前端(在www.somecompany.com处),而Django并没有提供AJAX请求.

I'm working on a project that uses the Django REST Framework as a backend (let's say at api.somecompany.com but has a React.js frontend (at www.somecompany.com) not served by Django that makes AJAX requests.

因此,我不能使用Django的传统方法,即让模板包含CSRF令牌,例如<form action="." method="post">{% csrf_token %}

I can't, therefore, use Django's traditional method of having the template include the CSRF token like this <form action="." method="post">{% csrf_token %}

我可以向Django REST Framework的api-auth\login\网址发出请求,该网址将返回以下标头: Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/-但随后我无法检索该cookie并通过X-CSRFToken与我的AJAX请求一起发回(我的理解是对单独的子域),而且它似乎没有自动包含在内.

I can make a request to Django REST Framework's api-auth\login\ url, which will return this header: Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/ - but I can't then retrieve this cookie to send back with my AJAX requests with X-CSRFToken (my understanding is of the separate subdomain), and it doesn't seem to be included automatically.

这是我的相关代码:

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    }
});

在页面加载时,我称其为确保拥有令牌:

As the page loads I call this to make sure I have a token:

$.ajax(loginUrl, { method: "OPTIONS", async: false })
    .done(function(data, textStatus, jqXHR) {
        console.log(jqXHR)
        app.csrftoken@ = $.cookie("csrftoken")
        console.log($.cookie("csrftoken"))
        console.log(app.csrftoken)
    })
    .fail(function(jqXHR, textStatus, errorThrown) {
        console.log(jqXHR)
    });

这还不是很干净,但是我还没有向我自己证明这个概念.

This isn't exactly clean but I haven't proven the concept to myself yet.

当前端和后端位于不同的端口/域上时,对CSRF进行身份验证/防护的正确"方法是什么?

What is the 'correct' way of authenticating / protecting against CSRF when the frontend and backend are on different ports/domains?

推荐答案

事实上,您可以使用允许的请求来源白名单来实现CSRF保护.

You can, as a matter of fact, make this work with CSRF protection, using a whitelist of allowed request origins.

要执行此操作,您将必须使用Cross-Origin Resource Sharing(CORS).为此,我建议创建一个中间件类来设置交叉共享凭据.有一个伟大的要旨概述了如何在跨源HTTP请求标头中使用某些构建.您可以根据需要通过更改请求的原始引用值,通过中间件以这种方式插入CSRF令牌.

To make this work, you're going to have to use Cross-Origin Resource Sharing (CORS). To achieve this, I'd recommend creating a middleware class that sets up your cross-sharing credentials. There's a great gist that outlines how to use some of the build in cross origin HTTP request headers. You can, if you want, insert the CSRF token via middleware in this way, by changing the origin reference values for the request.

django-cors-headers 应用会为您执行此操作.您可以在 their上了解他们如何协商CSRF令牌中间件文件(如果您有兴趣).

The django-cors-headers app does this for you. You can see how they've negotiated the CSRF tokens in their middleware file, if you're interested.

有关更多信息,请参见 Django REST CORS文档.对此(建议使用django-cors-headers).

Refer to the Django REST CORS Docs for more on this (they recommend using django-cors-headers).

如果您仍然遇到困难,请尝试:

If you're still having difficulties, try:

  1. 将AJAX请求的 crossDomain 参数设置为True.有时,如果未指定此请求,jQuery将不会处理该请求.
  2. 如果您仍然没有在请求中收到令牌头,请尝试附加
  1. setting the crossDomain parameter of your AJAX request to True. Sometimes, jQuery won't process the request if this isn't specified.
  2. if you're still not receiving a token header in the request at all, try appending the ensure_csrf_cookie() decorator around your view method. Occasionally, when there's no {% csrf_token %} template tag on the page (if you're not rendering a form), Django won't include the token in the request at all.

这篇关于如何作为API向Django检索CSRF令牌/从Django提供CSRF令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆