使用 PUT/DELETE 方法休息框架的“CSRF 令牌丢失”
Posted
技术标签:
【中文标题】使用 PUT/DELETE 方法休息框架的“CSRF 令牌丢失”【英文标题】:"CSRF token missing" with PUT/DELETE meethod rest-framework 【发布时间】: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”作为身份验证类之一。从设置中删除它,一切都应该正常工作。 【参考方案1】:在您的 REST_FRAMEWORK 设置中,您没有提到身份验证方案,因此 DRF 使用默认身份验证方案,即 SessionAuthentication。此方案强制要求您将 csrf 令牌与您的请求一起放置。你可以通过以下方式克服这个问题:
-
在 settings.py 中为整个项目进行此设置添加
REST_FRAMEWORK =
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
)
-
要在特定视图中进行此设置,请在您的视图中执行以下操作
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://***.com/a/26639895/3520792
参考:https://***.com/a/30875830/3520792
【讨论】:
“你总是可以通过 X-CSRFToken 标头传递 csrf_token”这正是我不知道该怎么做,因为我正在使用 ModelSetView 这与您使用的视图无关。您正在使用会话,服务器没有从客户端获取 csrf_token。您只需在 X-CSRFToken 请求标头中传递 csrf_token 。有一些方法可以在客户端获取 csrf_token。 ref:- ***.com/questions/22063612/… , ***.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'),
【讨论】:
以上是关于使用 PUT/DELETE 方法休息框架的“CSRF 令牌丢失”的主要内容,如果未能解决你的问题,请参考以下文章
Chrome 的插件 CORS Toggle 无法使用 POST/PUT/DELETE 方法
使用Spring boot开发RestFul 风格项目PUT/DELETE方法不起作用
nginx proxy_pass基于请求方法是POST,PUT还是DELETE
Ajax中Put和Delete请求传递参数无效的解决方法(Restful风格)