Django Rest Framework删除csrf

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使用的默认SessionAuthentication方案。 DRF的SessionAuthentication使用Django的会话框架进行身份验证,需要检查CSRF。

如果未在视图/视图集中定义任何authentication_classes,则DRF将使用此身份验证类作为默认值。

1
2
3
4
'DEFAULT_AUTHENTICATION_CLASSES'= (
    'rest_framework.authentication.SessionAuthentication',
    'rest_framework.authentication.BasicAuthentication'
),

由于DRF需要同时支持对相同视图的会话和非会话身份验证,因此它仅对经过身份验证的用户执行CSRF检查。这意味着只有经过身份验证的请求才需要CSRF令牌,并且可以在没有CSRF令牌的情况下发送匿名请求。

如果您正在使用带有SessionAuthentication的AJAX样式API,则需要为任何"不安全"HTTP方法调用(例如PUT, PATCH, POST or DELETE请求)包含有效的CSRF令牌。

该怎么办?

现在要禁用csrf检查,您可以创建一个自定义身份验证类CsrfExemptSessionAuthentication,它从默认的SessionAuthentication类扩展。在此身份验证类中,我们将覆盖实际SessionAuthentication内发生的enforce_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

在您的视图中,您可以将authentication_classes定义为:

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')

应该完成工作!


对于所有没有找到有用答案的人。是,如果您不使用SessionAuthentication AUTHENTICATION CLASS,DRF会自动删除CSRF保护,例如,许多开发人员仅使用JWT:

1
2
3
'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),

但问题CSRF not set可能是由于其他原因而发生的,例如,您没有正确添加路径到您查看:

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中删除Session Authentication,这将自动删除所有基于csrf的问题。但在这种情况下,Browseable apis可能无法正常工作。

此外,即使使用会话身份验证,也不会出现此错误您应该为您的api使用TokenAuthentication之类的自定义身份验证,并确保在您的请求中发送Accept:application/jsonContent-Type:application/json(假设您使用的是json)以及身份验证令牌。


我对同样的问题感到震惊。我按照这个参考,它工作。
解决方案是创建一个中间件

在你的一个应用程序中添加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


如果您为应用程序使用独占虚拟环境,则可以使用以下方法,而无需使用任何其他应用程序。

你观察到的是因为rest_framework/authentication.pySessionAuthentication类的authenticate方法中有这个代码:

1
self.enforce_csrf(request)

如果不需要CSRF检查,可以修改Request类以具有名为csrf_exempt的属性,并在相应的View类中将其初始化为True。例如:

接下来,修改上面的代码如下:

1
2
if not request.csrf_exempt:
    self.enforce_csrf(request)

Request类中,您必须进行一些相关的更改。这里提供了完整的实现(完整描述):https://github.com/piaxis/django-rest-framework/commit/1bdb872bac5345202e2f58728d0e7fad70dfd7ed


在DNS重新绑定攻击期间,这也可能是一个问题。

在DNS更改之间,这也可能是一个因素。等待DNS完全刷新将解决此问题,如果它在DNS问题/更改之前工作。