Api 密钥和 Django Rest Framework Auth Token

Posted

技术标签:

【中文标题】Api 密钥和 Django Rest Framework Auth Token【英文标题】:Api key and Django Rest Framework Auth Token 【发布时间】:2016-07-08 04:50:18 【问题描述】:

我已经在使用内置的 Django rest auth 令牌,并且我计划发布另一个 api,它将被外部集成调用以在我的 Django 应用程序中调用某些操作。问题是我想为此外部 api 调用生成另一个令牌,该调用必须与身份验证系统分开(例如 Mandrill API 密钥或 Github 个人访问令牌)。从Django rest框架authtokenModel生成api密钥是不是很好的解决方案?

外部 api 令牌:

必须永不过期(它可能在会话身份验证系统中过期) 可以链接到用户,但不是必需的(如果链接到帐户) 可以撤销并重新激活

你有释放 api 密钥的经验吗?

Django Rest Framework 有没有推荐的最佳实践?

谢谢;)

【问题讨论】:

你能分享一下你最后做了什么吗?我面临同样的限制.. 刚刚发布了我的代码作为答案***.com/a/38913644/2551769 【参考方案1】:

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

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

身份验证.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" 

【讨论】:

有一个过期的时间戳,不时自动更新令牌不是更好吗?还是在您的用例中不需要它?【参考方案2】:

djangorestframework-api-key 库目前可能是更好的选择。

来自文档:

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

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

最简单的集成:

# 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",
    ]

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

编辑:令牌也可以撤销

【讨论】:

【参考方案3】:

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

有了这个包,你可以

    设置过期时间 重新激活或撤销密钥 从对您的 api 的每次外部调用中确定令牌是否有效

还是

希望对您有所帮助。

【讨论】:

我在 django-rest-framework-jwt 中没有发现任何撤销和重新激活行为。与 Django rest authtoken 相比,价值在哪里? 这取决于你到底想做什么。一种解决方案是从请求标头中删除 json Web 令牌。并在需要时再次添加。

以上是关于Api 密钥和 Django Rest Framework Auth Token的主要内容,如果未能解决你的问题,请参考以下文章

Django Rest 框架的基于密钥的访问

Django REST框架--关系和超链接api

如何解决 django rest-framework 中的错误请求

如何修复 Reactjs、Django、Django Rest Frame 工作项目中的“net::ERR_CONNECTION_REFUSED 和错误:网络错误”错误

Django REST framework框架之GET, POST, PUT, PATCH, DELETE等API请求接口设计

我需要显示与相同模型有多对多关系的相关字段。 Django Rest Frame工作