Django手动检查CSRF令牌

时间:2015-04-05 05:06:26

标签: django django-csrf csrf-protection

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

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

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

4 个答案:

答案 0 :(得分:8)

您可以继承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(...)

答案 1 :(得分:3)

您可以使用内置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

答案 2 :(得分:2)

我一直在访问类似AldarundCsrfViewMiddleware,但需要更多关于此类解决方案的说法:

  1. 如果您在视图中执行测试,则可以直接返回reason。根据{{​​3}},当process_view返回除None之外的其他内容时,它必须是HttpResponse对象,因此它可以由视图返回。

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

  2. 如果您在普通视图中使用该测试,并且您已在站点范围内使用CsrfViewMiddleware,那么request通常已经过了一次通过CsrfViewMiddleware。 (是的,它可能会发生。我有一个案例,我收到的请求经过CsrfViewMiddleWare 修改并重新测试CsrfViewMiddleware由于网站而已经过测试 - 宽配置。)但是,中间件在测试后设置csrf_processing_done request,如果再次调用它,则不会再次测试它,因为这个标志。因此,csrf_processing_done必须重置为False才能执行第二次测试。

  3. 以上是对此的说明:

    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...
    

答案 3 :(得分:1)

就我而言,我想通过CSRF检查发布一些原始数据。

因此,我在用于处理POST数据的视图中使用此装饰器requires_csrf_token

from django.views.decorators.csrf import requires_csrf_token

@requires_csrf_token
def manage_trade_allocation_update(request):

在我的模板中,我添加了csrf_tokengénération并将其放在数据发布中:

{% csrf_token %}
...
data['csrfmiddlewaretoken'] = document.querySelector('input[name="csrfmiddlewaretoken"]').value;

借助这种机制,我可以将CSRF保护与手动HTTP POST请求结合使用。