Django 手动检查 CSRF 令牌
Posted
技术标签:
【中文标题】Django 手动检查 CSRF 令牌【英文标题】:Django check CSRF token manually 【发布时间】:2015-06-09 20:21:57 【问题描述】:我正在实现一个使用 API 密钥或 CSRF 令牌的 API。目标是让 Web 应用程序(受 CSRF 保护)或第三方应用程序(受 API 密钥保护)都可以使用它。
基本上对每个请求(全部通过 POST),我都会检查是否有 API 密钥。如果有一个有效的,那很好。如果没有,我想回退到验证 CSRF。
我可以调用一个函数来自己验证 CSRF 吗?视图本身是 @csrf_exempt
,因为 API 密钥需要工作。
【问题讨论】:
您不需要检查每个请求,因为 CSRF 令牌应该只用于 POST 和 PUT 请求。其次,您无法验证 CSRF 令牌,除非您在每个请求上都生成它,并且您的验证是可选。 CSRF 令牌与 API 密钥不同。请说明为什么需要 CSRF。 【参考方案1】:您可能可以继承 CsrfViewMiddleware 类并覆盖 process_view 方法。然后包含您的自定义中间件,而不是默认的 CSRF 中间件。
from django.middleware.csrf import CsrfViewMiddleware
class CustomCsrfMiddleware(CsrfViewMiddleware):
def process_view(self, request, callback, callback_args, callback_kwargs):
if request.META.get('api_key'):
# process api key
else:
return super(CsrfViewMiddleware, self).process_view(...)
【讨论】:
为了向其他人澄清,为了使用您的自定义中间件,请进入您的项目的 settings.py 文件,删除 MIDDLEWARE_CLASSESdjango.middleware.csrf.CsrfViewMiddleware
中的行并添加您自己的(即myApp.views.CustomCsrfMiddleware
)。很好的解决方案,谢谢!【参考方案2】:
您可以像这样使用内置的 csrf 验证:
from django.middleware.csrf import CsrfViewMiddleware
def check_csrf(request):
reason = CsrfViewMiddleware().process_view(request, None, (), )
if reason:
# CSRF failed
raise PermissionException() # do what you need to do here
【讨论】:
"reason" 在我的情况下始终是“无”。这在 2022 年仍然有效吗? (我使用基于类的视图)【参考方案3】:我一直在访问CsrfViewMiddleware
,就像Aldarund 显示的那样,但关于这种解决方案还有更多需要说明:
如果您在视图中执行测试,则可以直接返回reason
。根据how Django middleware works,当process_view
返回的不是None
,那么它必须是HttpResponse
对象,所以它只能被视图返回。
在某些情况下,您可能不想直接返回 reason
,但如果没有理由不这样做,我宁愿返回它,以与网站在其他情况下的行为保持一致。
CsrfViewMiddleWare
重新测试之后由于站点范围的配置,它已经被CsrfViewMiddleware
测试过。)但是,中间件在测试之后将csrf_processing_done
设置为request
,并且如果再次调用它就不会重新测试它,因为这个标志。所以csrf_processing_done
必须重置为False
才能执行第二次测试。
以下是上述内容的说明:
from django.middleware.csrf import CsrfViewMiddleware
def view(request):
request.csrf_processing_done = False
reason = CsrfViewMiddleware().process_view(request, None, (), )
if reason is not None:
return reason # Failed the test, stop here.
# process the request...
【讨论】:
【参考方案4】:就我而言,我想通过 CSRF 检查发布一些原始数据。
所以,我在处理 POST 数据的视图中使用了这个装饰器 requires_csrf_token:
from django.views.decorators.csrf import requires_csrf_token
@requires_csrf_token
def manage_trade_allocation_update(request):
在我的模板中,我添加了 csrf_token génération 并将其放入数据帖子中:
% csrf_token %
...
data['csrfmiddlewaretoken'] = document.querySelector('input[name="csrfmiddlewaretoken"]').value;
通过这种机制,我可以将 CSRF 保护与手动 HTTP POST 请求一起使用。
【讨论】:
以上是关于Django 手动检查 CSRF 令牌的主要内容,如果未能解决你的问题,请参考以下文章
如何忽略发送到 Django REST 框架的 CSRF 令牌?
Django Rest Framework 将不接受我的 CSRF 令牌