简体   繁体   English

如何将 csrf_token 传递给 django 中的 javascript 文件?

[英]how to pass csrf_token to javascript file in django?

Here is my javascript code that works fine.这是我的 javascript 代码,运行良好。 but I like to keep javascript files seperate and not use as inline script tags但我喜欢将 javascript 文件分开,而不是用作内联脚本标签

<script>
    $('.book').click(function() {
         var id= $(this).attr('id');
         data={
              'id':id,
              'csrfmiddlewaretoken':'{{ csrf_token }}',
              };
          $.ajax({
            url: '/post/book/',
            cache:'false',
            dataType:'json',
            type:'POST',
            data:data,
            success: function(data){
               //do something
              else {
                  //do something
              }
            }, 
            error: function(error){
              alert('error; '+ eval(error));
            }
          });
          return false;
      });
     });
</script>

I want to include this in my custom.js file that I have included in my base.html.我想将它包含在我的 base.html 中的 custom.js 文件中。 which is这是

{% load static from staticfiles %}
{% load bootstrap3 %}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>{% block title %}{% endblock %}</title>
  {% bootstrap_css %}
  <!-- Optional theme -->
  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css">
  <link href="{% static "css/custom.css" %}" rel="stylesheet">
  <!-- Latest compiled and minified JavaScript -->
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.js"></script>
  <script src="{% static "js/custom.js" %}" ></script>
  <script src="{% static "js/jquery.blockUI.js" %}"></script>
  {% bootstrap_javascript %}
  {% load bootstrap3 %}
{% load static from staticfiles %}
{% block content %} {% endblock %}

I am not able to reference csrf_token that is available in the current template in Django to the static js file.我无法将 Django 中当前模板中可用的csrf_token引用到static js文件。 how can I get this to work?我怎样才能让它工作?

If you want to reference template tags then you need that file to be templated (rendered) by Django.如果您想引用模板标签,那么您需要该文件由 Django 模板化(呈现)。 And I wouldn't recommend rendering all your static files via django...而且我不建议通过 django 渲染所有静态文件...

You can either put the csrf_token in a global variable that you then access from your script.您可以将 csrf_token 放在一个全局变量中,然后您可以从脚本访问该变量。 Something like this in your base.html:在你的 base.html 中是这样的:

<script>
    var csrftoken = '{{ csrf_token }}';
</script>

Or you can pull the csrftoken from the cookies in your javascript file.或者,您可以从 javascript 文件中的 cookie 中提取 csrftoken。 Seethis question for a solution for that.请参阅此问题以获取解决方案。 The cookie is called csrftoken .该 cookie 称为csrftoken You can view it by opening up your dev tools and looking at the cookies for your domain.您可以通过打开开发工具并查看域的 cookie 来查看它。

You can either access the CSRF token from 'csrftoken' cookie at the client using following function:您可以使用以下函数从客户端的“csrftoken”cookie 访问 CSRF 令牌:

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 = 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;
}

And calling it like:并称之为:

getCookie('csrftoken');

Or you may simply define a variable in HTML template and use that in your client side script.或者您可以简单地在 HTML 模板中定义一个变量并在您的客户端脚本中使用它。

<script>
    var CSRF_TOKEN = '{{ csrf_token }}';
</script>

The CSRF Token is available as a cookie on the page with the name "csrftoken". CSRF 令牌可用作页面上名为“csrftoken”的 cookie。 The Django docs suggest getting the cookie and passing it in the HTTP request headers as X-CSRFToken . Django 文档建议获取 cookie 并将其作为X-CSRFToken在 HTTP 请求标头中X-CSRFToken Then you can protect the view using the @csrf_protect decorator.然后您可以使用@csrf_protect装饰器保护视图。

Here are the Django docs on AJAX: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax .以下是 AJAX 上的 Django 文档: https : //docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

So using the jQuery cookie plugin , your code might look like:因此,使用jQuery cookie 插件,您的代码可能如下所示:

$.ajax({
  url: '/post/book/',
  cache: 'false',
  dataType: 'json',
  type: 'POST',
  data: data,
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRFToken', $.cookie('csrftoken')),
  },
  success: function(data) {},
  error: function(error) {}
});

In Django 2.x Reference: https://docs.djangoproject.com/en/2.2/ref/csrf/在 Django 2.x 参考: https : //docs.djangoproject.com/en/2.2/ref/csrf/

Here is a minimum example.这是一个最小的例子。

Fisrt insert your url in html template.首先在 html 模板中插入你的 url。

<input type="hidden" id="u_calc" data-url="{% url 'demo:calc' %}"/>

Then, get your url and csrf token from cookie.然后,从 cookie 中获取您的 url 和 csrf 令牌。 Use beforeSend in ajax request.在ajax请求中使用beforeSend

let u_calc = $("#u_calc").attr("data-url");

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 = 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;
}

var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function get_result(number) {
    let n = number.val();
    $.ajax({
        beforeSend: function (xhr, settings) {
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        },
        method: "POST",
        type: "POST",
        url: u_calc,
        async: true,
        dataType: "json",
        data: JSON.stringify({'number': n}),
        contentType: "application/json",
        success: function (data) {
            alert(data.result);
        },
    });
}

In views.py , the calc function may look likeviews.pycalc函数可能看起来像

def calc(request):
    if request.is_ajax() and request.method == "POST":
        data = json.loads(request.body)
        number = int(data["number"])
        return JsonResponse({"result": 2 * number})

You can pass csrf_token like this你可以像这样传递csrf_token

function deleteAccount(id, name) {
  if (confirm('Do you want to delete ' + name + '?')) {
    $.ajax({
      type: 'post',
      url: url,
      data: 'csrfmiddlewaretoken={{csrf_token}}',
      success: function() {
         window.location.reload(true);
      }
    });
  }
}
<button id="check_button" data-csrf="{{ csrf_token }}">
    button
</button>
$(document).ready(function() {
    $('#check_button').click(async function() {
        await fetch(url, {
            method: 'POST',
            headers: {
                'X-CSRFToken': $(this).data().csrf,
            },
            ...
        })
        ...
    })
})

You can just simply define it in the HTML template like:您可以简单地在 HTML 模板中定义它,例如:

<script>
var CSRF_TOKEN = '{{ csrf_token }}';
</script>

It will work它会工作

I've tried many ways to solve it and here's recap:我已经尝试了很多方法来解决它,这里是回顾:

  1. Using {{ csrf_token }} in a seperate js file doesn't work event you embed it into django template.在单独的 js 文件中使用 {{ csrf_token }} 不起作用,您将其嵌入到 django 模板中。

  2. Using @csrf_protect in your view doesn't works as well because it can only protect a part of function.在您的视图中使用 @csrf_protect 效果不佳,因为它只能保护部分功能。

  3. The right way to implement is here:正确的实现方法在这里:

    from django.views.decorators.csrf import csrf_exempt从 django.views.decorators.csrf 导入 csrf_exempt

Then before the view function, using @csrf_exempt: Here is an example然后在视图函数之前,使用@csrf_exempt:这里是一个例子

from django.views.decorators.csrf import csrf_exempt从 django.views.decorators.csrf 导入 csrf_exempt

@csrf_exempt @csrf_exempt

def function_name(request):定义函数名称(请求):

Your function here.你的功能在这里。

Hope it help希望有帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM