2016-03-21 102 views
5

我已經在使用內置的Django rest認證令牌,我打算髮佈一個其他的API,這個API將被外部集成調用,以便在我的Django應用程序中調用某些動作。問題是我想爲這個外部api調用生成另一個令牌,它必須與auth系統(f.i.,如Mandrill API Keys或Github Personal Access Token)分開。從Django rest framework authtoken模型生成api密鑰是否是一個很好的解決方案?Api鍵和Django Rest框架認證令牌

外部API令牌:

  • 必須永不過期(它可以在一個會話身份驗證系統失效)
  • 可能與用戶,但不是必需的(如果掛賬戶)
  • 可能被撤銷並重新激活

你有任何釋放api密鑰的經驗嗎?

它是由Django Rest Framework推薦的最佳實踐嗎?

謝謝;)

+0

你可以分享你最終做什麼?我面臨着相同的限制.. –

+0

剛剛發佈我的代碼作爲答案http://stackoverflow.com/a/38913644/2551769 – jsan

回答

7

我已經創建了一個新的身份驗證後端和一個新的令牌模型,以避免內置令牌行爲的副作用。

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) 

然後你就可以要求安全API和:

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

有沒有更好的時間戳到期並自動更新令牌一次?或者在你的用例中不需要? –

+0

我只需要一個永久性的api-key。 – jsan

2

如果我理解正確的話,那麼Json Web Tokens是您需要的解決方案。有一個非常好的django軟件包可以與django rest框架順利集成:django-rest-framework-jwt

有了這個包,你可以

  1. 設置過期時間
  2. 重新激活或撤銷鍵
  3. 從每一個外部調用您的API確定,如果令牌是有效

仍然

希望有所幫助。

+0

我沒有找到任何撤銷和重新激活django-rest-framework-jwt中的行爲。與Django rest'authtoken'比較的值在哪裏? – jsan

+0

這取決於你想要做什麼。一個解決方案是從請求頭中刪除json Web令牌。並在需要時再次添加。 – niklas