【问题标题】:"CSRF token missing" with PUT/DELETE meethod rest-framework使用 PUT/DELETE 方法休息框架的“CSRF 令牌丢失”
【发布时间】:2017-01-07 16:59:19
【问题描述】:

我正在使用带有 ModelViewSet 的 django rest 框架可浏览 api 来执行 CRUD 操作并希望使用权限。IsAuthenticatedOrReadOnly,但是当我登录并尝试 DELETE 或 PUT 时,我得到了 "detail": "CSRF Failed: CSRF token missing or incorrect."

我的视图是这样的

class objViewSet(viewsets.ModelViewSet):
    queryset = obj.objects.all()
    serializer_class = objSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

Settings.py

REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
    'rest_framework.permissions.AllowAny',
),

序列化器只是

class ObjSerializer(serializers.ModelSerializer):
    class Meta:
        model = Obj

虽然当我删除 permission_classes(所以默认的 allowAny 触发器)时,它可以正常工作。

我想要什么

只有在我通过身份验证后才能进行 PUT/DELETE。当一切自动发生时,我不知道如何发送 CSRF 令牌(modalviewset 完成整个工作)

【问题讨论】:

  • 您想全局删除 csrf 检查吗?还是单独的非 csrf 视图?
  • 如果您在这里找不到更好的解决方案,我敢打赌您正在使用“rest_framework.authentication.SessionAuthentication”作为身份验证类之一。从设置中删除它,一切都应该正常工作。

标签: python django rest


【解决方案1】:

在您的 REST_FRAMEWORK 设置中,您没有提到身份验证方案,因此 DRF 使用默认身份验证方案,即 SessionAuthentication。此方案强制要求您将 csrf 令牌与您的请求一起放置。你可以通过以下方式克服这个问题:

  1. 在 settings.py 中为整个项目进行此设置添加


    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
             'rest_framework.authentication.BasicAuthentication',
        )}

  1. 要在特定视图中进行此设置,请在您的视图中执行以下操作


    class objViewSet(viewsets.ModelViewSet):
        queryset = obj.objects.all()
        serializer_class = objSerializer
        permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
        authentication_classes = (BasicAuthentication,)

来源:http://www.django-rest-framework.org/api-guide/authentication/#sessionauthentication

顺便说一句,csrf 令牌保存为名为“csrftoken”的 cookie。您可以从 HTTP 响应中检索它,并使用密钥“X-CSRFToken”将其附加到您的请求标头。您可以在以下位置查看一些详细信息:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax

【讨论】:

    【解决方案2】:

    您可能一直对 csrf_token 使用 SessionAuthentication 和会话身份验证检查,您可以通过豁免来避免检查,但我们不要这样做。

    我认为您可以保留两个身份验证类。或者只是 TokenAuthentication。即,

    'DEFAULT_AUTHENTICATION_CLASSES': (
        # 'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    
        # 'oauth2_provider.ext.rest_framework.OAuth2Authentication',
        # 'rest_framework_social_oauth2.authentication.SocialAuthentication',
    ),
    

    如果您不打算使用 TokenAuth 而只是会话身份验证。您始终可以通过 X-CSRFToken 标头传递 csrf_token 。或者你可以去 csrf_except 东西。这将避免 csrf 丢失问题。

    这应该可行。另请参阅下面的链接。

    参考:https://stackoverflow.com/a/26639895/3520792

    参考:https://stackoverflow.com/a/30875830/3520792

    【讨论】:

    • “你总是可以通过 X-CSRFToken 标头传递 csrf_token”这正是我不知道该怎么做,因为我正在使用 ModelSetView
    • 这与您使用的视图无关。您正在使用会话,服务器没有从客户端获取 csrf_token。您只需在 X-CSRFToken 请求标头中传递 csrf_token 。有一些方法可以在客户端获取 csrf_token。 ref:- stackoverflow.com/questions/22063612/… , stackoverflow.com/questions/28417781/… 调查一下。它只是您的请求标头应该有它。
    • 我知道如何使用 ajax 从客户端执行此操作。但是我的客户端(可浏览的 api)是由 django 自动生成的,这意味着 - 我无权访问它。是否有任何选项可以在 django 代码中修改我的视图(因此它们包括 CSRFToken),或者我是否必须覆盖这个 borwsable api 视图,然后在单击“PUT”/“DELETE”时使用 ajax?
    • 我在本地也有同样的工作。我刚刚从 Django REST framework 3.2.4 提供的可浏览 API 接口检查了 API put post。它为我工作。使用答案中给出的设置。如果您正在做任何不同的事情,请帮助我重现它。
    【解决方案3】:

    您应该将 CSRF 令牌添加到您的请求中。如果您使用 JSON 请求执行此操作,则应将其添加到您的 JS 代码中。 它从用户 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 = 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');
    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);
            }
        }
    });
    

    【讨论】:

      【解决方案4】:

      您可以删除对单个 url 的 CSRF 检查。在你的 urls.py 上试试这个:

      url(r'^/my_url_to_view/', csrf_exempt(views.my_view_function), name='my_name'),
      

      【讨论】:

        猜你喜欢
        • 2019-10-08
        • 1970-01-01
        • 2017-01-29
        • 2020-11-23
        • 2017-10-02
        • 1970-01-01
        • 1970-01-01
        • 2020-01-17
        • 2021-07-14
        相关资源
        最近更新 更多