Django @csrf_exempt无法在课堂视图中工作

时间:2017-01-18 00:18:49

标签: django python-3.x django-rest-framework django-csrf

我在Django 1.9中有一个使用SessionMiddleware的应用程序。我想在同一个项目中为这个应用程序创建一个API,但在执行POST请求时,它不能用于@csrf_exempt注释。

我正在向Postman发出请求,这是我到目前为止所做的:

settings.py

MIDDLEWARE_CLASSES = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'a9.utils.middleware.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'a9.core.access.middleware.AccessMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',    
]

OAUTH2_PROVIDER = {
    # this is the list of available scopes
    'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'}
}

CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
)
CORS_ALLOW_HEADERS = (
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
)

REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
        #'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'oauth2_provider.ext.rest_framework.OAuth2Authentication',
        #'rest_framework.authentication.TokenAuthentication',
    )
}

urls.py

urlpatterns = [
    url(r'^v1/', include([
        url(r'^', include(router.urls)),
        url(r'^auth/', MyAuthentication.as_view()),
        url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
        url(r'^admin/', include(admin.site.urls)),
    ])),
]

views.py

@method_decorator(csrf_exempt, name='dispatch')
class MyAuthentication(TemplateView):

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

        return HttpResponse('Hello, World!')

在此之后,我总是得到CSRF验证失败错误。

我在django-rest-framework的IRC频道中问过这个问题,但我仍然没有答案。请,任何建议将非常感谢。

4 个答案:

答案 0 :(得分:3)

您需要在csrf_exempt方法中装饰dispatch

class MyView(FormView):

    @method_decorator(csrf_exempt)
    def dispatch(self, *args, **kwargs):
        return super(MyView, self).dispatch(*args, **kwargs)

    def post(self, request, *args, **kwargs):
        # ....
        return super(MyView, self).post(request, *args, **kwargs)

答案 1 :(得分:3)

不要在Django REST框架中使用csrf_exempt

这不会起作用,因为SessionAuthentication无论如何都会强制执行csrf检查。

请确保在AJAX请求中使用csrf令牌。 Django有a comprehensive documentation关于它

答案 2 :(得分:0)

我找到了解决这个问题的方法。您需要创建一个在任何会话中间件之前调用的中间件,然后检查您想要的URL或应用程序以免除CSRF令牌验证。所以,代码将是这样的:

<强> settings.py

match = ''
for string in myStringArray:
    if string in comment.body:
        match = string
        break

if match:
    pass # do stuff

<强> urls.py

MIDDLEWARE_CLASSES = [
    'api.middleware.DisableCSRF',  # custom middleware for API
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'a9.utils.middleware.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'a9.core.access.middleware.AccessMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
]

<强> csrf_disable.py

app_name = "api"

urlpatterns = [
    url(r'^v1/', include([
        url(r'^', include(router.urls)),
        url(r'^auth/', MyAuthentication.as_view()),
        url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
        url(r'^admin/', include(admin.site.urls)),
    ])),
]

这只会在不删​​除所有CSRF的情况下针对特定应用或网址检查CSRF令牌。另外,这是django-rest-framework independent :))

答案 3 :(得分:0)

就我而言,在 django3.2 中使用 DRF 和基于函数的视图。我必须明确地将 permission_classes 设置为 []

@api_view(["GET"])
@permission_classes([])
def ping(*args, **kwargs):
    """
    Used to double check that the api is up an running.
    """
    return Response({"msg": "pong"}, status=200)

我相信基于类的视图可能类似:

class PingView(ListAPIView):
    permission_classes = []
    pagination_class = None
    serializer_class = None
    def get(self):
        return Response({"msg": "pong"}, status=200)