我正在实现一个API,它可以使用API密钥或CSRF令牌。目标是使其可由Web应用程序(受到CSRF保护)或第三方应用程序(受API密钥保护)使用。
基本上,在每个请求(全部通过POST)上,我都会检查是否存在API密钥。如果有有效的API密钥,则可以进行下一步操作。如果没有,则要回退到验证CSRF。
是否有一个函数可以调用来验证CSRF?视图本身是 @csrf_exempt
,因为API密钥需要工作。
我正在实现一个API,它可以使用API密钥或CSRF令牌。目标是使其可由Web应用程序(受到CSRF保护)或第三方应用程序(受API密钥保护)使用。
基本上,在每个请求(全部通过POST)上,我都会检查是否存在API密钥。如果有有效的API密钥,则可以进行下一步操作。如果没有,则要回退到验证CSRF。
是否有一个函数可以调用来验证CSRF?视图本身是 @csrf_exempt
,因为API密钥需要工作。
你可以通过继承CsrfViewMiddleware类并重写process_view方法来实现自定义CSRF中间件。然后用你的自定义中间件替换默认的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(...)
django.middleware.csrf.CsrfViewMiddleware
,并添加您自己的中间件(例如 myApp.views.CustomCsrfMiddleware
)。非常好的解决方案,谢谢! - InnisBrendanfrom 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
我一直在像Aldarund所展示的那样访问CsrfViewMiddleware
,但还需要更多关于这种解决方案的说明:
如果你在视图中执行测试,那么你可以直接返回 reason
。根据 Django middleware的工作原理,当 process_view
返回除 None
以外的内容时,它必须是一个 HttpResponse
对象,因此它可以被视图直接返回。
可能有些情况下你不想直接返回 reason
,但如果没有任何理由不这样做,我更愿意这样做,以保持网站在其他情况下的一致性。
如果你在普通视图中使用测试,并且你已经在整个网站中使用了 CsrfViewMiddleware
,那么通常情况下,request
已经通过 CsrfViewMiddleware
进行了一次传递。(是的,这种情况可能发生。我有一个情况,在这种情况下,我收到的请求被修改并重新通过 CsrfViewMiddleWare
测试,尽管它已经被 CsrfViewMiddleware
测试过了,这是由于网站范围的配置。)然而,中间件在测试完毕后会在 request
上设置 csrf_processing_done
标志,并且如果再次调用它,它将不会重新测试它,因为有了这个标志。因此,必须将 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...
在我的情况下,我想要进行CSRF检查并POST一些原始数据。
因此,我在处理POST数据的视图中使用了这个装饰器requires_csrf_token:
from django.views.decorators.csrf import requires_csrf_token
@requires_csrf_token
def manage_trade_allocation_update(request):
{% csrf_token %}
...
data['csrfmiddlewaretoken'] = document.querySelector('input[name="csrfmiddlewaretoken"]').value;