通过我的AJAX帖子,我可以使用一些帮助来遵守Django的CSRF保护机制。我遵循了这里的说明:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/

我已经复制了他们在该页面上的AJAX示例代码:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

我把一个警告打印getCookie('csrftoken')的内容之前的xhr。setRequestHeader调用,它确实被一些数据填充。我不确定如何验证令牌是正确的,但我被鼓励它正在寻找和发送一些东西。

但是Django仍然拒绝我的AJAX帖子。

这是我的JavaScript:

$.post("/memorize/", data, function (result) {
    if (result != "failure") {
        get_random_card();
    }
    else {
        alert("Failed to save card data.");
    }
});

下面是我从Django中看到的错误:

[23/Feb/2011 22:08:29] "POST / remember / HTTP/1.1" 403 2332

我肯定我遗漏了什么,也许很简单,但我不知道是什么。我在SO周围搜索了一下,看到了一些关于通过csrf_exempt装饰器关闭视图的CSRF检查的信息,但我发现那没什么吸引力。我已经尝试过了,它是有效的,但如果可能的话,我宁愿让我的POST以Django设计的方式工作。

为了以防有用,这里是我的视图正在做的事情的要点:

def myview(request):

    profile = request.user.profile

    if request.method == 'POST':
        """
        Process the post...
        """
        return HttpResponseRedirect('/memorize/')
    else: # request.method == 'GET'

        ajax = request.GET.has_key('ajax')

        """
        Some irrelevent code...
        """

        if ajax:
            response = HttpResponse()
            profile.get_stack_json(response)
            return response
        else:
            """
            Get data to send along with the content of the page.
            """

        return render_to_response('memorize/memorize.html',
                """ My data """
                context_instance=RequestContext(request))

谢谢你的回复!


当前回答

与所选答案相关,只是想对所选答案进行补充。

在这个回答中,关于. ajaxsetup(…)的解决方案。在Django settings.py中,如果你有

CSRF_USE_SESSIONS = True

这将导致所选的答案根本不起作用。在实现所选答案的解决方案时,删除该行或将其设置为False对我有用。

有趣的是,如果你在Django settings.py中设置了以下内容

CSRF_COOKIE_HTTPONLY = True

此变量不会导致所选答案的解决方案停止工作。

CSRF_USE_SESSIONS和CSRF_COOKIE_HTTPONLY都来自这个官方的Django文档https://docs.djangoproject.com/en/2.2/ref/csrf/

(我没有足够的代表来评论,所以我张贴我的输入一个答案)

其他回答

我有一个解决办法。在我的JS我有两个函数。 首先得到饼干(即。csrftoken):

function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
    const cookies = document.cookie.split(';');
    for (let i = 0; i < cookies.length; i++) {
        const cookie = cookies[i].trim();
        // 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;

}

第二个是我的ajax函数。在这种情况下,它是用于登录的,实际上不返回任何东西,只是传递值来设置一个会话:

function LoginAjax() {


    //get scrftoken:
    const csrftoken = getCookie('csrftoken');

    var req = new XMLHttpRequest();
    var userName = document.getElementById("Login-Username");
    var password = document.getElementById("Login-Password");

    req.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {            
            //read response loggedIn JSON show me if user logged in or not
            var respond = JSON.parse(this.responseText);            
            alert(respond.loggedIn);

        }
    }

    req.open("POST", "login", true);

    //following header set scrftoken to resolve problem
    req.setRequestHeader('X-CSRFToken', csrftoken);

    req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    req.send("UserName=" + userName.value + "&Password=" + password.value);
}

公认的答案很可能是在转移注意力。Django 1.2.4和1.2.5之间的区别在于AJAX请求需要CSRF令牌。

我在Django 1.3上遇到了这个问题,这是由于CSRF cookie一开始就没有设置造成的。除非必须,否则Django不会设置cookie。因此,在Django 1.2.4上运行的纯ajax或重度ajax站点可能永远不会向客户端发送令牌,然后需要令牌的升级将导致403错误。

理想的解决方法是: http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form 但是您必须等到1.4版本,除非这只是文档与代码同步

Edit

还要注意的是,Django文档在jQuery 1.5中指出了一个bug,所以确保你使用的是1.5.1或更高版本的Django建议代码: https://docs.djangoproject.com/en/dev/ref/csrf/#ajax

你可以把这个js粘贴到你的html文件中,记住把它放在其他js函数之前

<script>
  // 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));
  }

  $(document).ready(function() {
    var csrftoken = getCookie('csrftoken');
    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
  });
</script>

与所选答案相关,只是想对所选答案进行补充。

在这个回答中,关于. ajaxsetup(…)的解决方案。在Django settings.py中,如果你有

CSRF_USE_SESSIONS = True

这将导致所选的答案根本不起作用。在实现所选答案的解决方案时,删除该行或将其设置为False对我有用。

有趣的是,如果你在Django settings.py中设置了以下内容

CSRF_COOKIE_HTTPONLY = True

此变量不会导致所选答案的解决方案停止工作。

CSRF_USE_SESSIONS和CSRF_COOKIE_HTTPONLY都来自这个官方的Django文档https://docs.djangoproject.com/en/2.2/ref/csrf/

(我没有足够的代表来评论,所以我张贴我的输入一个答案)

One CSRF token is assigned to every session ( i.e. every time you log in). So before you wish to get some data entered by user and send that as ajax call to some function which is protected by csrf_protect decorator, try to find the functions that are being called before you are getting this data from user. E.g. some template must be being rendered on which your user is entering data. That template is being rendered by some function. In this function you can get csrf token as follows: csrf = request.COOKIES['csrftoken'] Now pass this csrf value in context dictionary against which template in question is being rendered. Now in that template write this line: Now in your javascript function, before making ajax request, write this: var csrf = $('#csrf').val() this will pick value of token passed to template and store it in variable csrf. Now while making ajax call, in your post data, pass this value as well : "csrfmiddlewaretoken": csrf

这将工作,即使你没有实现django表单。

实际上,这里的逻辑是:您需要从请求中获得的令牌。 因此,您只需要在登录后立即找出被调用的函数。一旦你有了这个令牌,要么进行另一个ajax调用来获取它,要么将它传递给一些可以通过ajax访问的模板。