Api密钥和Django Rest Framework Auth Token

jsa*_*san 9 python authentication django api-key django-rest-framework

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

外部api令牌:

  • 必须永不过期(它可能会在会话auth系统中失效)
  • 可以链接到用户但不是必需的(如果链接到帐户)
  • 可以被撤销和重新激活

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

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

谢谢 ;)

jsa*_*san 11

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

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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

然后你可以通过以下方式申请安全api:

curl http://example.com/api/your-awesome-api.json -H "Authorization: Api-Key {token}" 
Run Code Online (Sandbox Code Playgroud)


err*_*ynn 5

目前图书馆djangorestframework-api-key可能是更好的选择。

来自文档:

Django REST Framework API Key 是一个功能强大的库,允许服务器端客户端安全地使用您的 API。这些客户端通常是第三方后端和服务(即机器),它们没有用户帐户,但仍需要以安全的方式与您的 API 交互。

这是一种受良好支持且易于使用的方式,可以手动或以编程方式为 Django REST Framework 项目发布新的 API 密钥。

最简单的集成:

# settings.py

INSTALLED_APPS = [
  # ...
  "rest_framework",
  "rest_framework_api_key",
]
Run Code Online (Sandbox Code Playgroud)
python manage.py migrate
Run Code Online (Sandbox Code Playgroud)
# settings.py
REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework_api_key.permissions.HasAPIKey",
    ]
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过管理界面或通过对象以编程方式创建新的 API 密钥rest_framework_api_key.models.APIKey

编辑:令牌也可以被撤销