Django手动检查CSRF令牌

Luk*_*pan 10 django django-csrf csrf-protection

我正在实现一个API,它既可以使用API​​密钥,也可以使用CSRF令牌.目标是通过Web应用程序(受CSRF保护)或第三方应用程序(受API密钥保护)使用它.

基本上每个请求(都通过POST),我检查是否有API密钥.如果有一个有效的,那就好了.如果没有,我想回到验证CSRF.

我可以打电话来验证CSRF吗?视图本身是@csrf_exempt因为API密钥需要工作.

bva*_*ugt 9

您可以继承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(...)
Run Code Online (Sandbox Code Playgroud)


Ald*_*und 5

您可以像这样使用内置的 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
Run Code Online (Sandbox Code Playgroud)


Lou*_*uis 5

我一直在访问AldarundCsrfViewMiddleware所展示的内容,但关于这种解决方案还需要说更多:

  1. 如果你是在视图中执行测试,那么你可以reason直接返回。根据Django 中间件的工作原理,当process_view返回的内容不是 时None,那么它必须是一个HttpResponse对象,因此它只能由视图返回。

    在某些情况下,您可能不想reason直接返回,但如果没有理由不这样做,我宁愿返回它,以与网站在其他情况下的行为保持一致。

  2. 如果您在普通视图中使用测试,并且已经在CsrfViewMiddleware站点范围内使用,则通常情况下request已经通过了一次CsrfViewMiddleware。(是的,这可能会发生。我有一种情况,由于站点范围的配置,我收到的请求在经过测试CsrfViewMiddleWare 后被修改并重新测试。)但是,中间件在测试后启动并不会'由于这个标志,如果再次调用它,则不会重新测试它。因此必须重置才能执行第二次测试。CsrfViewMiddlewarecsrf_processing_donerequestcsrf_processing_doneFalse

这是上面的一个例子:

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