2015-04-05 9 views
9

Sto implementando un'API che funziona con una chiave API o con un token CSRF. L'obiettivo è che sia utilizzabile da un'app Web (protetta da CSRF) o da un'applicazione di terze parti (protetta dalla chiave API).Django controlla token CSRF manualmente

Fondamentalmente su ogni richiesta (tutta via POST), controllo se c'è una chiave API. Se ce n'è uno valido, è bello andare. In caso contrario, voglio tornare a verificare CSRF.

Esiste una funzione che posso chiamare per verificare personalmente il CSRF? La vista stessa è @csrf_exempt perché le chiavi API devono funzionare.

+0

Non è necessario controllare su ciascuna richiesta, come i token CSRF in realtà dovrebbe essere utilizzato solo su POST e PUT richieste. In secondo luogo, non è possibile verificare un token CSRF a meno che non lo si generi su ogni richiesta e la verifica è _optional_. Un token CSRF non è uguale a una chiave API. Per favore chiarisci perché hai bisogno di CSRF. –

risposta

5

Probabilmente si potrebbe creare una sottoclasse della classe CsrfViewMiddleware e sovrascrivere il metodo process_view. Quindi includi il middleware personalizzato al posto di quello predefinito 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

Per chiarire per gli altri, per utilizzare il middleware personalizzato, vai nel tuo file settings.py per il tuo progetto, elimina la riga in MIDDLEWARE_CLASSES 'django.middleware.csrf.CsrfViewMiddleware' e aggiungi il tuo (es.' MyApp.views .CustomCsrfMiddleware'). Ottima soluzione, grazie! – grez

3

È possibile utilizzare la verifica CSRF incorporato in questo modo:

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

ho accesso a CsrfViewMiddleware come Aldarund ha dimostrato, ma più deve essere detto su questo tipo di soluzione:

  1. Se si sta eseguendo il test in una vista, è possibile restituire direttamente reason. Secondo how Django middleware works, quando process_view restituisce qualcosa di diverso da None, quindi deve essere un oggetto HttpResponse in modo che possa essere restituito dalla vista.

    Ci possono essere casi in cui non si desidera restituire direttamente reason, ma se non c'è motivo per non farlo, preferirei restituirlo, per coerenza con il comportamento del sito in altri casi.

  2. se si utilizza il test in una vista run-of-the-mill, e si utilizza già a livello di sito CsrfViewMiddleware, di solito è il caso che request avranno già passati una volta attraverso CsrfViewMiddleware. (Sì, può succedere. Ho un caso in cui una richiesta che ricevo viene modificato e rianalizzato attraverso CsrfViewMiddleWaredopo è già stato testato da CsrfViewMiddleware a causa della configurazione a livello di sito.) Tuttavia, il middleware imposta csrf_processing_done su request dopo lo verifica e non lo ripeterà nuovamente se viene richiamato, a causa di questa bandiera. Quindi csrf_processing_done deve essere reimpostato su False per eseguire un secondo test.

Ecco un esempio di quanto sopra:

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