Django Rest Framework remove csrf
我知道有关于Django Rest Framework的答案,但我无法找到解决问题的方法。
我有一个具有身份验证和一些功能的应用程序。
我添加了一个新的应用程序,它使用Django Rest Framework。 我想只在这个应用程序中使用该库。 我也想发出POST请求,我总是收到这个回复:
1 2 3 | { "detail":"CSRF Failed: CSRF token missing or incorrect." } |
我有以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # urls.py from django.conf.urls import patterns, url urlpatterns = patterns( 'api.views', url(r'^object/$', views.Object.as_view()), ) # views.py from rest_framework.views import APIView from rest_framework.response import Response from django.views.decorators.csrf import csrf_exempt class Object(APIView): @csrf_exempt def post(self, request, format=None): return Response({'received data': request.data}) |
我想添加API而不影响当前的应用程序。
所以我的问题是如何才能为此应用禁用CSRF?
为什么会出现这种错误?
这是因为DRF使用的默认
如果未在视图/视图集中定义任何
1 2 3 4 | 'DEFAULT_AUTHENTICATION_CLASSES'= ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication' ), |
由于DRF需要同时支持对相同视图的会话和非会话身份验证,因此它仅对经过身份验证的用户执行CSRF检查。这意味着只有经过身份验证的请求才需要CSRF令牌,并且可以在没有CSRF令牌的情况下发送匿名请求。
如果您正在使用带有SessionAuthentication的AJAX样式API,则需要为任何"不安全"HTTP方法调用(例如
该怎么办?
现在要禁用csrf检查,您可以创建一个自定义身份验证类
1 2 3 4 5 6 | from rest_framework.authentication import SessionAuthentication, BasicAuthentication class CsrfExemptSessionAuthentication(SessionAuthentication): def enforce_csrf(self, request): return # To not perform the csrf check previously happening |
在您的视图中,您可以将
1 | authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication) |
这应该处理csrf错误。
更简单的解决方案
在views.py中,使用大括号CsrfExemptMixin和authentication_classes:
1 2 3 4 5 6 7 8 9 10 11 12 | # views.py from rest_framework.views import APIView from rest_framework.response import Response from django.views.decorators.csrf import csrf_exempt from braces.views import CsrfExemptMixin class Object(CsrfExemptMixin, APIView): authentication_classes = [] def post(self, request, format=None): return Response({'received data': request.data}) |
修改urls.py
如果您在urls.py中管理路由,则可以使用csrf_exempt()包装所需的路由,以将它们从CSRF验证中间件中排除。
1 2 3 4 5 6 7 8 | from django.conf.urls import patterns, url from django.views.decorators.csrf import csrf_exempt import views urlpatterns = patterns('', url(r'^object/$', csrf_exempt(views.ObjectView.as_view())), ... ) |
或者,作为装饰者
有些人可能会发现使用@csrf_exempt装饰器更适合他们的需要
例如,
1 2 3 4 5 6 | from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse @csrf_exempt def my_view(request): return HttpResponse('Hello world') |
应该完成工作!
对于所有没有找到有用答案的人。是,如果您不使用
1 2 3 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', ), |
但问题
1 | url(r'^api/signup/', CreateUserView), # <= error! DRF cant remove CSRF because it is not as_view that does it! |
代替
1 | url(r'^api/signup/', CreateUserView.as_view()), |
如果您不想使用基于会话的身份验证,则可以从REST_AUTHENTICATION_CLASSES中删除
此外,即使使用会话身份验证,也不会出现此错误您应该为您的api使用TokenAuthentication之类的自定义身份验证,并确保在您的请求中发送
我对同样的问题感到震惊。我按照这个参考,它工作。
解决方案是创建一个中间件
在你的一个应用程序中添加disable.py文件(在我的情况下是'myapp')
1 2 3 | class DisableCSRF(object): def process_request(self, request): setattr(request, '_dont_enforce_csrf_checks', True) |
并将middileware添加到MIDDLEWARE_CLASSES
1 2 3 | MIDDLEWARE_CLASSES = ( myapp.disable.DisableCSRF, ) |
我尝试了上面的一些答案,觉得创建一个单独的课程有点过分了。
作为参考,我在尝试将基于函数的视图方法更新为基于类的用户注册视图方法时遇到了这个问题。
使用基于类的视图(CBV)和Django Rest Framework(DRF)时,从ApiView类继承并将permission_classes和authentication_classes设置为空元组。 在下面找一个例子。
1 2 3 4 5 6 7 8 | class UserRegistrationView(APIView): permission_classes = () authentication_classes = () def post(self, request, *args, **kwargs): # rest of your code here |
我的解决方案显示出来了。装饰我的班级。
1 2 3 4 5 6 7 | from django.views.decorators.csrf import csrf_exempt @method_decorator(csrf_exempt, name='dispatch') @method_decorator(basic_auth_required( target_test=lambda request: not request.user.is_authenticated ), name='dispatch') class GenPedigreeView(View): pass |
如果您为应用程序使用独占虚拟环境,则可以使用以下方法,而无需使用任何其他应用程序。
你观察到的是因为
1 | self.enforce_csrf(request) |
如果不需要CSRF检查,可以修改
接下来,修改上面的代码如下:
1 2 | if not request.csrf_exempt: self.enforce_csrf(request) |
在
在DNS重新绑定攻击期间,这也可能是一个问题。
在DNS更改之间,这也可能是一个因素。等待DNS完全刷新将解决此问题,如果它在DNS问题/更改之前工作。