2016-03-21 33 views
5

Sto già utilizzando token di autenticazione resto Django incorporato e pianifico di rilasciare un'altra API che verrà chiamata da integrazioni esterne per chiamare qualche azione nella mia applicazione Django. Il problema è che voglio generare un altro token per questa chiamata API esterna che deve essere separata dal sistema di autenticazione (ad esempio Mandrill API Keys o Github Personal Access Token). È una buona soluzione per generare chiavi API dal framework di restituzione di Django authtoken Modello?Chiave Api e Django Rest Framework Autenticazione Token

token dell'API esterna:

  • non deve mai scadere (potrebbe scadere in un sistema di sessione di autenticazione)
  • potrebbe essere collegato ad utente ma non obbligatorio (se collegato al conto)
  • potrebbe essere revocata e riattivato

Hai qualche esperienza con il rilascio di chiavi API?

È una buona pratica consigliata da Django Rest Framework?

Grazie;)

+0

Puoi condividere che cosa si finisce per fare? Sto affrontando gli stessi vincoli .. –

+0

Ho appena pubblicato il mio codice come risposta http://stackoverflow.com/a/38913644/2551769 – jsan

risposta

7

Ho creato un nuovo backend di autenticazione e un nuovo modello di token per evitare effetti collaterali sul comportamento dei token build-in.

models.py

class ApiKeyToken(models.Model): 
    key = models.CharField(max_length=40, primary_key=True) 
    company = models.ForeignKey(Company) 
    is_active = models.BooleanField(default=True) 

    def save(self, *args, **kwargs): 
     if not self.key: 
      self.key = self.generate_key() 
     return super(ApiKeyToken, self).save(*args, **kwargs) 

    def generate_key(self): 
     return binascii.hexlify(os.urandom(20)).decode() 

    def __unicode__(self): 
     return self.key 

authentication.py

class ApiKeyAuthentication(TokenAuthentication): 

    def get_token_from_auth_header(self, auth): 
     auth = auth.split() 
     if not auth or auth[0].lower() != b'api-key': 
      return None 

     if len(auth) == 1: 
      raise AuthenticationFailed('Invalid token header. No credentials provided.') 
     elif len(auth) > 2: 
      raise AuthenticationFailed('Invalid token header. Token string should not contain spaces.') 

     try: 
      return auth[1].decode() 
     except UnicodeError: 
      raise AuthenticationFailed('Invalid token header. Token string should not contain invalid characters.') 

    def authenticate(self, request): 
     auth = get_authorization_header(request) 
     token = self.get_token_from_auth_header(auth) 

     if not token: 
      token = request.GET.get('api-key', request.POST.get('api-key', None)) 

     if token: 
      return self.authenticate_credentials(token) 

    def authenticate_credentials(self, key): 
     try: 
      token = ApiKeyToken.objects.get(key=key) 
     except ApiKeyToken.DoesNotExist: 
      raise AuthenticationFailed('Invalid Api key.') 

     if not token.is_active: 
      raise AuthenticationFailed('Api key inactive or deleted.') 

     user = token.company.users.first() # what ever you want here 
     return (user, token) 

Poi si può richiedere api protetta con:

curl http://example.com/api/your-awesome-api.json -H "Authorization: Api-Key {token}" 
+0

Non sarebbe meglio avere un timestamp con scadenza e rinnovare il token automaticamente una volta ogni tanto? o non è necessario nel tuo caso d'uso? –

+0

Nel mio caso ho solo bisogno di una chiave API permanente. – jsan

2

Se ho capito bene, poi Json Web Tokens è la soluzione per le vostre esigenze. È disponibile un ottimo pacchetto django che si integra perfettamente con il framework django rest: django-rest-framework-jwt.

Con questo pacchetto

  1. è possibile impostare l'ora di scadenza
  2. riattivare o revocare la chiave
  3. determinare da ogni chiamata esterna al vostro api, se il token è valido

Still

Spero che questo aiuti.

+0

Non trovo alcuna revoca e riattivo il comportamento in django-rest-framework-jwt. Dov'è il valore rispetto a Django resto 'authtoken'? – jsan

+0

dipende da ciò che volevi esattamente fare. Una soluzione sarebbe rimuovere il token web json dall'intestazione della richiesta. e aggiungilo di nuovo quando necessario. – niklas