如何仅在某些情况下禁用 Django 的 csrf 保护?

Posted

技术标签:

【中文标题】如何仅在某些情况下禁用 Django 的 csrf 保护?【英文标题】:How can I disable Django's csrf protection only in certain cases? 【发布时间】:2012-07-07 15:09:16 【问题描述】:

我正在尝试在 Django 中编写一个站点,其中 API URL 与面向用户的 URL 相同。但是我在处理使用 POST 请求和 CSRF 保护的页面时遇到了问题。例如,如果我有一个页面 /foo/add 我希望能够通过两种方式向它发送 POST 请求:

    作为最终用户(使用会话 cookie 进行身份验证)提交表单。这需要 CSRF 保护。 作为 API 客户端(使用 HTTP 请求标头进行身份验证)。如果启用 CSRF 保护,这将失败。

我找到了各种禁用 CSRF 的方法,例如 @csrf_exempt,但这些都在整个视图中禁用它。有没有办法在更细粒度的级别启用/禁用它?还是我只需要从头开始实施自己的 CSRF 保护?

【问题讨论】:

你检查csrf protection docs了吗? 我已经阅读了一些内容,但显然没有阅读所有场景。谢谢! 【参考方案1】:

Django 的 CSRF 保护文档中有一个标题为 View needs protection for one path 的部分描述了一个解决方案。这个想法是在整个视图上使用@csrf_exempt,但是当API客户端标头不存在或无效时,然后调用一个函数 用@csrf_protect注解。

【讨论】:

【参考方案2】:

修改urls.py

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

例如,

from django.views.decorators.csrf import csrf_exempt
urlpatterns = patterns(
    # ...
    # Will exclude `/api/v1/test` from CSRF 
    url(r'^api/v1/test', csrf_exempt(TestApiHandler.as_view()))
    # ...
)

或者,作为装饰者

有些人可能会发现使用@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')

【讨论】:

【参考方案3】:

如果您正在使用类基视图 (CBV) 并希望使用 csrf_exempt 装饰器,则需要使用方法装饰器。

from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt

@method_decorator(csrf_exempt, name='dispatch')
class MyView(View):
    def post(self, request):
        pass  # my view code here

【讨论】:

你确定这个解决方案吗?【参考方案4】:

就我而言,我使用 JWT 身份验证和 csrf_token 来获取某些视图。由于某些我不知道的原因,csrf_exempt 在我将其设置为装饰器或将视图名称包装在 url 模式中时不起作用。

所以这就是我最终要做的。我覆盖了APIView 类中的initialize_request

class ClasssName(views.APIView):
    def initialize_request(self, request, *args, **kwargs):
        setattr(request, 'csrf_processing_done', True) 
        return super().initialize_request(request, *args, **kwargs)

【讨论】:

以上是关于如何仅在某些情况下禁用 Django 的 csrf 保护?的主要内容,如果未能解决你的问题,请参考以下文章

如何仅在 localhost 的 Spring Security 中禁用 csrf?

Django学习之禁用csrf和使用csrf操作详解

CodeIgniter 仅在某些页面使用 CSRF 保护

如何启用/禁用提交按钮,仅在提供两个条件的情况下:检查输入单选和填充输入文本

Django:在所有响应上强制 CSRF 令牌

只有在 Flutter 应用程序上使用 Web 时,如何才能禁用某些功能?