Api密钥和Django Rest Framework Auth Token

时间:2022-04-27 03:42:18

I'm already using build-in Django rest auth token and I plan to release an other api that will be called by an external integrations to call some action in my Django application. The issue is that I want to generate an other token for this external api call that must be separate from auth system (f.i. like Mandrill API Keys or Github Personal Access Token). Is it a good solution to generate api keys from Django rest framework authtoken Model ?

我已经在使用内置的Django rest auth令牌了,我打算发布一个其他的api,它将被外部集成调用,以便在我的Django应用程序中调用一些动作。问题是我想为这个外部api调用生成另一个令牌,该令牌必须与auth系统分开(f.i.如Mandrill API Keys或Github Personal Access Token)。从Django rest framework authtoken Model生成api密钥是一个很好的解决方案吗?

External api token:

外部api令牌:

  • must never expire (it could expire in a session auth system)
  • 必须永不过期(它可能会在会话auth系统中到期)
  • could be linked to user but not required (if linked to account)
  • 可以链接到用户但不是必需的(如果链接到帐户)
  • could be revoked and reactivated
  • 可以撤销并重新激活

Do you have any experience with releasing api keys ?

你有发布api密钥的经验吗?

Is it any best practice recommended by Django Rest Framework ?

这是Django Rest Framework推荐的最佳实践吗?

Thank you ;)

谢谢 ;)

2 个解决方案

#1


7  

I have created a new authentication backend and a new token model to avoid side effect on build-in token behaviour.

我创建了一个新的身份验证后端和一个新的令牌模型,以避免对内置令牌行为产生副作用。

models.py

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

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)

Then you can request secured api with:

然后您可以通过以下方式请求安全api:

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

#2


2  

If I understand you correctly, then Json Web Tokens is the solution for your needs. There is a really good django package available that integrates smoothly with django rest framework: django-rest-framework-jwt.

如果我理解正确,那么Json Web Tokens就是满足您需求的解决方案。有一个非常好的django包可以与django rest框架顺利集成:django-rest-framework-jwt。

With this package you can

有了这个包,你可以

  1. set the expiration time
  2. 设置到期时间
  3. reactivate or revoke the key
  4. 重新激活或撤消密钥
  5. determine from every external call to your api, if the token is valid
  6. 如果令牌有效,则从每次外部呼叫确定您的api

Still

仍然

Hope that helps.

希望有所帮助。

#1


7  

I have created a new authentication backend and a new token model to avoid side effect on build-in token behaviour.

我创建了一个新的身份验证后端和一个新的令牌模型,以避免对内置令牌行为产生副作用。

models.py

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

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)

Then you can request secured api with:

然后您可以通过以下方式请求安全api:

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

#2


2  

If I understand you correctly, then Json Web Tokens is the solution for your needs. There is a really good django package available that integrates smoothly with django rest framework: django-rest-framework-jwt.

如果我理解正确,那么Json Web Tokens就是满足您需求的解决方案。有一个非常好的django包可以与django rest框架顺利集成:django-rest-framework-jwt。

With this package you can

有了这个包,你可以

  1. set the expiration time
  2. 设置到期时间
  3. reactivate or revoke the key
  4. 重新激活或撤消密钥
  5. determine from every external call to your api, if the token is valid
  6. 如果令牌有效,则从每次外部呼叫确定您的api

Still

仍然

Hope that helps.

希望有所帮助。