简体   繁体   中英

Api key and Django Rest Framework Auth Token

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 (fi like Mandrill API Keys or Github Personal Access Token). Is it a good solution to generate api keys from Django rest framework authtoken Model ?

External api token:

  • must never expire (it could expire in a session auth system)
  • 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 ?

Is it any best practice recommended by Django Rest Framework ?

Thank you ;)

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

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)

Then you can request secured api with:

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

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 .

With this package you can

  1. set the expiration time
  2. reactivate or revoke the key
  3. determine from every external call to your api, if the token is valid

Still

Hope that helps.

The djangorestframework-api-key library may be a better option currently.

From the docs:

Django REST Framework API Key is a powerful library for allowing server-side clients to safely use your API. These clients are typically third-party backends and services (ie machines) which do not have a user account but still need to interact with your API in a secure way.

It's a well-supported and simple-to-use way of releasing new API keys manually or programatically for Django REST Framework projects.

Simplest integration:

# settings.py

INSTALLED_APPS = [
  # ...
  "rest_framework",
  "rest_framework_api_key",
]
python manage.py migrate
# settings.py
REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework_api_key.permissions.HasAPIKey",
    ]
}

Then you can create new API keys through admin interface or programatically through the rest_framework_api_key.models.APIKey object.

Edit: Tokens can be revoked as well

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM