2015-04-05 92 views
9

我正在實現一個可與API密鑰或CSRF令牌一起使用的API。目標是通過Web應用程序(受CSRF保護)或第三方應用程序(受API密鑰保護)來使用它。Django手動檢查CSRF令牌

基本上每個請求(都通過POST),我檢查是否有一個API密鑰。如果有一個有效的,這是很好的去。如果不是,我想回到驗證CSRF。

是否有我可以調用來驗證CSRF的函數?該視圖本身是@csrf_exempt,因爲API密鑰需要工作。

+0

你並不需要檢查每個請求,如CSRF令牌應該只有真正地在使用POST和PUT請求。其次,除非您在每個請求上生成CSRF標記,否則您無法驗證CSRF標記,並且您的驗證是_optional_。 CSRF令牌與API密鑰不同。請說明你爲什麼需要CSRF。 – 2015-04-05 05:20:16

回答

5

您可能繼承了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(...) 
+0

要澄清他人,爲了使用您的自定義中間件,進入您的項目的settings.py文件,刪除MIDDLEWARE_CLASSES'django.middleware.csrf.CsrfViewMiddleware'中的行並添加自己的(即'myApp.views .CustomCsrfMiddleware')。很好的解決方案,謝謝 – grez 2016-05-24 22:13:58

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 
1

我已經訪問CsrfViewMiddlewareAldarund表明而是這種解決方案可說的更多的需求:

  1. 如果您在視圖中執行測試,那麼您可以直接返回reason。根據how Django middleware works,當process_view返回的東西不是None,那麼它必須是一個HttpResponse對象,因此它只能由視圖返回。

    有些情況下您不想直接返回reason,但如果沒有理由不這樣做,我寧願返回它,以便與其他情況下網站的行爲一致。

  2. 如果您使用測試在運行的設施,工廠的視圖,並且您已經使用CsrfViewMiddleware站點範圍內,通常是request將已經通過CsrfViewMiddleware穿過一次的情況。 (是的,它可能發生。我在哪裏接收的請求它已由CsrfViewMiddleware測試由於站點範圍的配置之後修改並重新測試通過CsrfViewMiddleWare的情況下)。然而,中間件後設置csrf_processing_donerequest它會對它進行測試,如果因爲此標誌而再次被調用,則不會重新測試它。因此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...