使用PUT / DELETE meethod rest-framework的“CSRF令牌丢失”

时间:2016-08-31 08:00:27

标签: python django rest

我正在使用django rest框架browsable api和ModelViewSet来做CRUD操作并且想要使用permissions.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',
),

Serializer就是

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

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

我想要什么

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

4 个答案:

答案 0 :(得分:3)

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

  1. 要在settings.py中为整个项目进行此设置,请添加
  2. 
    
        REST_FRAMEWORK = {
            'DEFAULT_AUTHENTICATION_CLASSES': (
                 'rest_framework.authentication.BasicAuthentication',
            )}
    
    
    1. 要在特定视图中进行此设置,请在视图中执行以下操作
    2. 
      
          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

      BTW,csrf令牌被保存为名为“csrftoken”的cookie。您可以从HTTP响应中检索它,并使用键“X-CSRFToken”将其附加到您的请求标头。您可以在https://docs.djangoproject.com/en/dev/ref/csrf/#ajax

      上查看有关此内容的详细信息

答案 1 :(得分:0)

您可能始终对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,只需要会话Auth。你总是可以通过X-CSRFToken标头传递csrf_token。或者你可以去csrf_except的东西。这将避免csrf丢失的问题。

这应该有效。另请参阅以下链接。

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

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

答案 2 :(得分:0)

您应该在请求中添加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);
        }
    }
});

答案 3 :(得分:-2)

您可以删除个别网址上的CSRF检查。在你的urls.py上试试这个:

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