【问题标题】:403 Forbidden error when making an ajax Post request in Django framework在 Django 框架中发出 ajax Post 请求时出现 403 禁止错误
【发布时间】:2013-10-20 10:00:08
【问题描述】:

我正在尝试将 jquery 集成到我使用 Django 框架制作的 Web 应用程序中。然而,我很难尝试拨打一个简单的ajax 电话来工作。我的模板文件包含表单 html 和 javascript 来处理 ajax 调用,如下所示:

<script type="text/javascript">
$(document).ready(function() {
$( "#target" ).submit(function() {
console.log('Form was submitted');
$.ajax({
        type: "POST",
        url: "/hello/",  // or just url: "/my-url/path/"
        data: {
            query: $( "#query" ).val()   
        },
        success: function(data) {
            console.log(data);
        }
    });
return false;
  });   
  })
</script>
<form id="target" action="." method="post">{% csrf_token %}
 <input id= "query" type="text" value="Hello there">
 <input type="submit" value="Search Recent Tweets">
</form>

我的 views.py 应该处理 ajax 调用看起来像:

 from django.core.context_processors import csrf
 from django.shortcuts import render_to_response
 from django.template.loader import get_template
 from django.template import Context,RequestContext
 from django.views.decorators.csrf import ensure_csrf_cookie
 from django.http import HttpResponse

 # access resource
 def hello(request):
  c = {}
  c.update(csrf(request))
  if request.is_ajax():
        t = get_template('template.html')
        #html = t.render(Context({'result': 'hello world'}))
        con = RequestContext(request, {'result': 'hello world'})
        return render_to_response('template.html', c, con)
  else:
        return HttpResponse('Not working!') 

我尝试关注Cross-Site Request Forgery Protection 上的官方文档,并查看了几个解决类似问题的stackoverflow 问题。我已将{% csrf_token %} 包含在我的html 模板文件中,但它似乎仍然无法正常工作。我在控制台中收到一个错误,提示 ajax 调用失败:

POST http://127.0.0.1:8000/hello/ 403 (FORBIDDEN)   

如何将result 变量与我的http 响应一起传递并让ajax 调用顺利工作?任何帮助都深表感谢。

Edit-1

据说我没有将csrf 令牌与我的发布请求一起传递。所以根据文档,我将以下代码添加到我的模板 javascript:

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;
}
var csrftoken = getCookie('csrftoken');
console.log(csrftoken);

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

当我在浏览器中刷新模板html页面时,在控制台得到null,提示cookie未设置或未定义。我错过了什么?

【问题讨论】:

    标签: jquery ajax django post


    【解决方案1】:

    因为你没有发布 csrfmiddlewaretoken,所以 Django 禁止你。 this document可以帮到你。

    【讨论】:

    • 我已根据您的建议更新了我的问题。我仍然得到同样的错误。如果你能告诉我你是如何工作的,我将不胜感激。
    • "csrfmiddlewaretoken"是你发布的数据中的一个key,例如,当你需要ajax登录时,你发布的数据可能是这样的:{'username':'username','password':'密码','csrfmiddlewaretoken':'CSRF-TOKEN-VALUE'}
    • 谢谢@PYTY,这就是问题所在。我没有嵌入令牌。
    • 你的链接失效了,链接改成这个:docs.djangoproject.com/en/1.7/ref/contrib/csrf/#ajax
    • 我知道这已经有一段时间了,但是即使您在 settings.py 中禁用了 csrf 中间件,这仍然适用吗?
    【解决方案2】:

    对于懒人:

    第一次下载cookie:http://plugins.jquery.com/cookie/

    将其添加到您的 html 中:

    <script src="{% static 'designer/js/jquery.cookie.js' %}"></script>
    

    现在您可以创建一个有效的 POST 请求:

    var csrftoken = $.cookie('csrftoken');
    
    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) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    });
    
    $.ajax(save_url, {
        type : 'POST',
        contentType : 'application/json',
        data : JSON.stringify(canvas),
        success: function () {
            alert("Saved!");
        }
    
    })
    

    【讨论】:

    • 我按照上面的代码,现在可以发送 ajax() 帖子,但它不会读取我的数据/参数。示例数据:{"name":"John Birada"}。 name 参数始终为空。谢谢
    【解决方案3】:

    如果您没有将 js 嵌入模板中,最快的解决方案是:

    &lt;script type="text/javascript"&gt; window.CSRF_TOKEN = "{{ csrf_token }}"; &lt;/script&gt; 放在模板中您对script.js 文件的引用之前,然后将csrfmiddlewaretoken 添加到您的data 字典中:

    $.ajax({
                type: 'POST',
                url: somepathname + "do_it/",
                data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
                success: function() {
                    console.log("Success!");
                }
            })
    

    如果您确实将 js 嵌入到模板中,则很简单:data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

    【讨论】:

      【解决方案4】:

      我在现场找到所有以前的答案,但让我们把事情放在上下文中。

      403禁止响应来自CSRF中间件(见Cross Site Request Forgery protection):

      默认情况下,如果传入请求未通过 CsrfViewMiddleware 执行的检查,则会向用户发送“403 Forbidden”响应。

      许多选项可用。我建议遵循answer of @fivef 以使jQuery 在每个带有$.ajaxSetup 的AJAX 请求之前添加X-CSRFToken 标头。

      这个答案需要 cookie 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;
      }
      var csrftoken = getCookie('csrftoken');
      

      但是:如果设置 CSRF_COOKIE_HTTPONLY 设置为 True,这通常会按照 Security middleware 的建议发生,那么即使使用了 @ensure_csrf_cookie(),cookie 也不存在。在这种情况下,{% csrf_token %} 必须以每种形式提供,这会产生像 &lt;input name="csrfmiddlewaretoken" value="cr6O9...FUXf6" type="hidden"&gt; 这样的输出。因此,csrfToken 变量将简单地通过以下方式获得:

      var csrftoken = $('input[name="csrfmiddlewaretoken"]').val();
      

      当然需要$.ajaxSetup

      其他可用但不推荐的选项是使用@csrf_exempt()禁用特定表单的中间件或csrf保护。

      【讨论】:

      • 终于通过你的评论弄明白了怎么回事。他们绝对应该将此添加到 csrf ajax 文档中。我不知道CSRF_COOKIE_HTTPONLY 破坏了我的 ajax 帖子。
      【解决方案5】:
      data: {"csrfmiddlewaretoken" : "{{csrf_token}}"}
      

      您会看到“403 (FORBIDDEN)”,因为您没有发送“csrfmiddlewaretoken”参数。 在模板中,每个表单都有这个:{% csrf_token %}。 您应该将“csrfmiddlewaretoken”添加到您的 ajax 数据字典中。我的示例是将“product_code”和“csrfmiddlewaretoken”发送到应用程序“basket”视图“remove”:

      $(function(){
          $('.card-body').on('click',function(){
              $.ajax({
                type: "post",
                url: "{% url 'basket:remove'%}",
                data: {"product_code": "07316", "csrfmiddlewaretoken" : "{{csrf_token}}" }
              });
          })
      });
      

      【讨论】:

      • 您好 AndrewPt,请考虑解释一下您到底做了什么,或者至少解释一下您的代码做了什么,以便阅读代码的人了解您在做什么。谢谢!
      • 嗨,Vishrut Mavani,我已经添加了解释!
      • 完美而直接的答案
      【解决方案6】:

      确保您没有缓存您的表单正在显示的页面/视图。它可能正在缓存您的 CSRF_TOKEN。发生在我身上!

      【讨论】:

        【解决方案7】:

        要设置 cookie,请在视图中使用 ensure_csrf_cookie 装饰器:

        from django.views.decorators.csrf import ensure_csrf_cookie
        
        @ensure_csrf_cookie
        def hello(request):
            code_here()
        

        【讨论】:

        • 你有中间件'django.middleware.csrf.CsrfViewMiddleware',在你的settings.py`的MIDDLEWARE_CLASSES中?
        • 是的,@kelvinss,我在 settings.py 中做了必要的更改
        【解决方案8】:

        另一种方法是添加带有“{{ csrf_token }}”值的 X-CSRFTOKEN 标头,如下例所示:

        $.ajax({
                    url: "{% url 'register_lowresistancetyres' %}",
                    type: "POST",
                    headers: {//<==
                                "X-CSRFTOKEN": "{{ csrf_token }}"//<==
                        },
                    data: $(example_form).serialize(),
                    success: function(data) {
                        //Success code
                    },
                    error: function () {
                        //Error code
                    }
                });
        

        【讨论】:

          【解决方案9】:

          尝试在你的调度代码中包含这个装饰器

          from django.utils.decorators import method_decorator
          from django.views.decorators.csrf import csrf_exempt     
          @method_decorator(csrf_exempt, name='dispatch')
          def dispatch(self, request, *args, **kwargs):
               return super(LessonUploadWorkView,self).dispatch(request,*args,**kwargs)
          

          【讨论】:

          • 不推荐csrf_exempt
          【解决方案10】:

          使用 SSL/https 和 CSRF_COOKIE_HTTPONLY = False,我仍然没有 csrftoken 在 cookie 中,使用 django Doc 中提出的 getCookie(name) 函数或 jquery .cookie.jsfivef提出。

          Wtower 总结是完美的,我认为从 settings.py 中删除 CSRF_COOKIE_HTTPONLY 后它会起作用,但它在 https 中没有!

          为什么 csrftoken 在 document.cookie 中不可见???

          而不是得到

          "django_language=fr;csrftoken=rDrGI5cp98MnooPIsygWIF76vuYTkDIt"

          我只得到

          “django_language=fr”

          为什么?就像SSL/https removes X-CSRFToken from headers 一样,我认为这是由于 Nginx 的代理标头参数,但显然不是......有什么想法吗?

          django doc Notes 不同,在带有 https 的 cookie 中使用 csrf_token 似乎是不可能的。传递 csrftoken 的唯一方法是通过 DOM 在 html 中使用 {% csrf_token %} 并在 jQuery 中使用

          var csrftoken = $('input[name="csrfmiddlewaretoken"]').val();
          

          然后可以通过标头 (xhr.setRequestHeader) 或 params 将其传递给 ajax。

          【讨论】:

            【解决方案11】:

            这对我有用

            模板.html

              $.ajax({
                url: "{% url 'XXXXXX' %}",
                type: 'POST',
                data: {modifica: jsonText, "csrfmiddlewaretoken" : "{{csrf_token}}"},
                traditional: true,
                dataType: 'html',
                success: function(result){
                   window.location.href = "{% url 'XXX' %}";
                    }
            });
            

            view.py

            def aggiornaAttivitaAssegnate(request):
                if request.is_ajax():
                    richiesta = json.loads(request.POST.get('modifica'))
            

            【讨论】:

              【解决方案12】:

              您必须更改文件夹 chmod 755 和文件 (.php ,.html) chmod 644。

              【讨论】:

                猜你喜欢
                • 2023-03-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-08-10
                • 2017-11-09
                • 2019-05-08
                • 2018-02-21
                相关资源
                最近更新 更多