Django Rest Framework删除csrf

Ire*_*xas 95 django csrf django-csrf django-rest-framework

我知道有关于Django Rest Framework的答案,但我无法找到解决问题的方法.

我有一个具有身份验证和一些功能的应用程序.我添加了一个新的应用程序,它使用Django Rest Framework.我想只在这个应用程序中使用该库.我也想发出POST请求,我总是收到这个回复:

{
    "detail": "CSRF Failed: CSRF token missing or incorrect."
}
Run Code Online (Sandbox Code Playgroud)

我有以下代码:

# 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})
Run Code Online (Sandbox Code Playgroud)

我想添加API而不影响当前的应用程序.所以我的问题是如何才能为此应用禁用CSRF?

Rah*_*pta 190

为什么会出现这种错误?

这是因为SessionAuthenticationDRF使用的默认方案.DRF SessionAuthentication使用Django的会话框架进行身份验证,需要检查CSRF.

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

'DEFAULT_AUTHENTICATION_CLASSES'= (
    'rest_framework.authentication.SessionAuthentication',
    'rest_framework.authentication.BasicAuthentication'
),
Run Code Online (Sandbox Code Playgroud)

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

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

该怎么办?

现在要禁用csrf检查,您可以创建一个CsrfExemptSessionAuthentication从默认SessionAuthentication类扩展的自定义身份验证类.在此身份验证类中,我们将覆盖enforce_csrf()实际内部发生的检查SessionAuthentication.

from rest_framework.authentication import SessionAuthentication, BasicAuthentication 

class CsrfExemptSessionAuthentication(SessionAuthentication):

    def enforce_csrf(self, request):
        return  # To not perform the csrf check previously happening
Run Code Online (Sandbox Code Playgroud)

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

authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)
Run Code Online (Sandbox Code Playgroud)

这应该处理csrf错误.

  • 对不起,也许我错过了这一点,但绕过/禁用csrf保护不存在安全风险吗? (7认同)
  • 谢谢,很好的答案.在restframework中应该有内置的方法来做到这一点,但目前这是我找到的最佳解决方案. (3认同)
  • @Paolo OP 需要禁用特定 API 的 CSRF 身份验证。但是,是的,禁用 csrf 保护存在安全风险。如果需要为特定用例禁用会话身份验证,则可以使用此解决方案。 (3认同)
  • @jsmedmar在Django 2.1中对我来说工作正常 (2认同)

bix*_*e57 15

更简单的解决方案

在views.py中,使用大括号CsrfExemptMixin和authentication_classes:

# 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})
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这是解决问题的最简单方法。我的 api 使用 oauth2_provider 和令牌。 (3认同)
  • 仅供参考, authentication_classes 行似乎是关键。无论有没有 CsrfExemptMixin,对我来说都是一样的。 (3认同)
  • 啊啊啊啊啊 我有 CsrfExemptMixin,但没有 authentication_classes = []。谢谢! (2认同)

Sye*_*zan 12

修改urls.py

如果您在urls.py中管理路由,则可以使用csrf_exempt()包装所需的路由,以将它们从CSRF验证中间件中排除.

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())),
    ...
)
Run Code Online (Sandbox Code Playgroud)

或者,作为装饰器,有些人可能会发现使用@csrf_exempt装饰器更适合他们的需要

例如,

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')
Run Code Online (Sandbox Code Playgroud)

应该完成工作!

  • DRF 的 APIView 和 ViewSetMixin 已经使用了“csrf_exempt”装饰器。不起作用,因为“enforce_csrf”对“check.process_view”的调用没有传递装饰视图(第二个参数是“None”)。 (4认同)
  • 这不适用于 Django REST Framework。 (3认同)

use*_*125 9

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

'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
Run Code Online (Sandbox Code Playgroud)

但问题CSRF not set可能是由于另一个原因造成的,例如,您没有正确添加路径给您查看:

url(r'^api/signup/', CreateUserView),  # <= error! DRF cant remove CSRF because it is not as_view that does it!
Run Code Online (Sandbox Code Playgroud)

代替

url(r'^api/signup/', CreateUserView.as_view()),
Run Code Online (Sandbox Code Playgroud)


hsp*_*her 7

如果您不想使用基于会话的身份验证,则可以Session Authentication从REST_AUTHENTICATION_CLASSES中删除,这将自动删除所有基于csrf的问题.但在这种情况下,Browseable apis可能无法正常工作.

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


Mik*_*wes 5

我尝试了上面的一些答案,并觉得创建一个单独的类有点麻烦。

作为参考,当尝试将基于函数的视图方法更新为用于用户注册的基于类的视图方法时,我遇到了此问题。

使用基于类的视图(CBV)和Django Rest框架(DRF)时,从ApiView类继承,并将Permission_classes和authentication_classes设置为空元组。在下面找到一个例子。

class UserRegistrationView(APIView):

    permission_classes = ()
    authentication_classes = ()

    def post(self, request, *args, **kwargs):

        # rest of your code here
Run Code Online (Sandbox Code Playgroud)


Nou*_*lie 5

您需要添加此内容以防止默认会话身份验证:(settings.py)

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated', 
    )
}
Run Code Online (Sandbox Code Playgroud)

然后:(views.py)

from rest_framework.permissions import AllowAny

class Abc(APIView):
    permission_classes = (AllowAny,)

    def ...():
Run Code Online (Sandbox Code Playgroud)


fan*_*nni 5

您需要绝对确定您想要关闭 CSRF 保护。

\n
    \n
  1. 创建文件authentication.py并将其放置在项目中您想要的任何位置。例如,在文件夹session_utils.
  2. \n
  3. 将此代码放入文件中:
  4. \n
\n
from rest_framework.authentication import SessionAuthentication\n\n\nclass SessionCsrfExemptAuthentication(SessionAuthentication):\n    def enforce_csrf(self, request):\n        pass\n\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 当您想要向您的视图发出POSTPUTPATCHDELETE请求时,请确保您已从新文件更改SessionAuthentication为。SessionCsrfExemptAuthentication查看示例:
  2. \n
\n
    @api_view(["POST"])\n    @authentication_classes([SessionCsrfExemptAuthentication])\n    @permission_classes([IsAuthenticated])\n    def some_view(request) -> "Response":\n        # some logic here\n        return Response({})\n
Run Code Online (Sandbox Code Playgroud)\n

这个技巧允许你覆盖方法(pass),enforce_csrf并且新的会话身份验证类将跳过 CSRF 检查。

\n

\xe2\x9c\x8c\xef\xb8\x8f

\n