我正在实现一个API,它既可以使用API密钥,也可以使用CSRF令牌。目标是使其可以通过Web应用程序(受CSRF保护)或第三方应用程序(受API密钥保护)使用。
基本上每个请求(都是通过POST),我检查是否有API密钥。如果有一个有效的,那就好了。如果没有,我想回到验证CSRF。
我可以打电话来验证CSRF吗?视图本身为@csrf_exempt
,因为API密钥需要工作。
答案 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)
我一直在访问类似Aldarund的CsrfViewMiddleware
,但需要更多关于此类解决方案的说法:
如果您在视图中执行测试,则可以直接返回reason
。根据{{3}},当process_view
返回除None
之外的其他内容时,它必须是HttpResponse
对象,因此它可以由视图返回。
在某些情况下,您可能不希望直接返回reason
,但如果没有理由不这样做,我宁愿将其返回,以便与网站在其他网站中的行为保持一致例。
如果您在普通视图中使用该测试,并且您已在站点范围内使用CsrfViewMiddleware
,那么request
通常已经过了一次通过CsrfViewMiddleware
。 (是的,它可能会发生。我有一个案例,我收到的请求经过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...
答案 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请求结合使用。