【问题标题】:Django rest framework ajax form submit error 403 (forbidden)Django rest框架ajax表单提交错误403(禁止)
【发布时间】:2021-09-25 14:18:46
【问题描述】:

当我尝试提交使用 DRF API 的 ajaxified 表单时,我会进入浏览器控制台!

POST http://localhost:8000/api/texts/ 403(禁止)

这是我的 html 文件:

 <form id="text-form" method="POST" action="">
                   

                            <input type="text" name="title" placeholder="Title" class="form-control mb-3 pb-2"
                                maxlength="200" required id="title">
                            <input type="date" name="deadline" placeholder="Deadline" autocomplete="off"
                                class="form-control mb-3" id="myflatpickr">                                         
                      
                            <textarea name="requirements" cols="40" rows="4"
                                placeholder="requirements"
                                class="form-control col mt-3" maxlength="200" required id="requirements"></textarea>

                    <textarea name="document" cols="40" rows="10"
                        placeholder="document"
                        id="editor" class="form-control" required></textarea>

                <button type="submit">Submit</button>
                </form>

这是我的 javascript 文件

  $("#text-form").submit(function (event) {
    event.preventDefault();
    $textData = $("#text-form").serialize()
    $.ajax({
      url: "http://localhost:8000/api/texts/",
      method: "POST",
      data: $textData,
      success: function() {
        console.log($textData)
      },
      error: function() {
        console.log("there is an error")

      }
    })

  });

在 serializers.py 中:


from django.contrib.auth import get_user_model
from django.contrib.auth.password_validation import validate_password
from rest_framework import serializers
from .models import *



class TextSerializer(serializers.ModelSerializer):
     author = serializers.HiddenField(
         default=serializers.CurrentUserDefault()
     )
     class Meta:
         model = Text
         fields = '__all__'

在我的views.py文件中:


class ApiTextList(generics.ListCreateAPIView):

    queryset = Text.objects.all()
    serializer_class = TextSerializer
    permission_classes = [
        permissions.AllowAny
    ]


class ApiTextDetail(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):

    http_method_names = ['get', 'head']
    queryset = Text.objects.all()
    serializer_class = TextSerializer
    permission_classes = [
        permissions.AllowAny
    ]

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

在 urls.py 中

from django.urls import path
from . import views


urlpatterns = [

    path('api/texts/', views.ApiTextList.as_view()),
    path('api/texts/<int:pk>/', views.ApiTextDetail.as_view()),
    
    
]

注意:当我尝试从 drf 在“localhost:8000/api/texts”中提供的界面添加文本时,我通常会添加它

【问题讨论】:

  • 您如何验证用户身份?当您将请求发送到api/texts 时,您似乎没有任何标头
  • 响应的detail字段中是否有关于错误的详细信息?
  • @bdbd 我正在使用 django 的默认身份验证系统以及登录和身份验证功能对用户进行身份验证
  • @Mickaelmartinez 哦,我没有注意到,它说“详细信息:“CSRF 失败:CSRF 令牌丢失或不正确。” ' 请注意,我有另一个用户注册表单,其代码相同,但没有 csrf 令牌,你能解释一下为什么它在没有 csrf 令牌的情况下工作

标签: python python-3.x django ajax django-rest-framework


【解决方案1】:

您收到错误 403,这意味着服务器理解请求但拒绝授权。您需要在发送 ajax 请求时添加授权令牌。

您可以使用它在您的页面上授权令牌。

<script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script>

然后,您必须将令牌添加到您的 ajax 请求中。

$.ajax({
  url: "http://localhost:8000/api/texts/",
  method: "POST",
  data: $textData,

  csrfmiddlewaretoken: window.CSRF_TOKEN,

  success: function() {
    console.log($textData)
  },
  error: function() {
    console.log("there is an error")

  }
})

【讨论】:

  • 我按照你说的做了,但我仍然遇到同样的问题!,我尝试在表单上和表单外添加
  • 我刚刚注意到,在响应的详细信息字段中显示“详细信息:“CSRF 失败:CSRF 令牌丢失或不正确。”“
【解决方案2】:

既然您告诉了我们详细信息字段的内容,应该更容易解决您的问题。

Django documentation 建议您从 cookie 中获取 CSRF 令牌。

它甚至为您提供了以下功能:

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

然后您可以通过添加这两行轻松地修改自己的代码:

$("#text-form").submit(function (event) {
    event.preventDefault();
    const csrftoken = getCookie('csrftoken'); // HERE: get the token 
    $textData = $("#text-form").serialize()
    $.ajax({
        url: "http://localhost:8000/api/texts/",
        method: "POST",
        data: $textData,
        headers:{"X-CSRFToken": csrftoken }, // HERE: add it to the request header
        success: function() {
            console.log($textData)
        },
        error: function() {
            console.log("there is an error")
        }
    })
});

如果这不起作用,请检查您是否正确使用Session Authentication

为了回答您的其他询问,您的注册视图在没有 CSRF 令牌的情况下工作是正常的:在 DRF 中,只有您需要进行身份验证的视图才需要它。

【讨论】:

    猜你喜欢
    • 2017-11-09
    • 1970-01-01
    • 2012-05-20
    • 1970-01-01
    • 2019-05-08
    • 2017-06-11
    • 2013-10-20
    • 2018-02-28
    • 2017-03-23
    相关资源
    最近更新 更多