【问题标题】:Django Rest Framework - Generate a Token for a non-built-in User model classDjango Rest Framework - 为非内置用户模型类生成令牌
【发布时间】:2021-03-16 23:23:36
【问题描述】:

我想知道我是否能够为普通模型类创建一个 Token。假设我有以下课程:

class User(models.Model):
    name                    = models.CharField(max_length=30, unique=True)
    profile_pic             = models.FileField(upload_to='None/',default='placeholder.jpg')
    joined_date             = models.DateTimeField(verbose_name='date joined', auto_now_add=True)

请注意,我的 User 类没有扩展 auth.models.User

现在当我使用这样的信号时:

@receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    if created:
        Token.objects.create(user=instance)

然后 Django 声明 Token.user 不是 User 的实例。基本上和this SO thread一样。

从上面的链接中,我了解到我的User 类必须扩展Django 提供的内置auth.models.User 类以进行身份​​验证。

但我很好奇,想知道是否有办法为不扩展 auth.models.User 的类生成令牌?那可能吗 ?如果是,如何?

【问题讨论】:

    标签: django django-rest-framework django-authentication


    【解决方案1】:

    #1 方法

    我们正在这里尝试生成令牌。根据定义,令牌是随机生成的字符序列。从其余身份验证令牌模型中汲取灵感,我们可以有一个类似的自定义模型。我们将覆盖此模型的保存方法以生成密钥。

    import binascii
    import os
    
    from django.db import models
    from django.utils.translation import ugettext_lazy as _
    
    class NonBuiltInUserToken(models.Model):
        ...
        key: str = models.CharField(_("Key"), max_length=40, primary_key=True)
        user: User = models.OneToOneField(
                User, related_name='auth_token',
                on_delete=models.CASCADE, 
                verbose_name=_("User")
        )
        created = models.DateTimeField(_("Created"), auto_now_add=True)
        ...
    
        class Meta:
            verbose_name = _("Token")
            verbose_name_plural = _("Tokens")
    
        def save(self, *args, **kwargs):
            if not self.key:
                self.key = self.generate_key()
            return super(NonBuiltInUserToken, self).save(*args, **kwargs)
    
        def generate_key(self):
            return binascii.hexlify(os.urandom(20)).decode()
    
        def __str__(self):
            return self.key
    

    复制自this stack overflow answer

    #2 方法

    您也可以尝试将身份验证令牌的令牌模型子类化。

    ...
    from django.db import models
    from django.utils.translation import gettext_lazy as _
    from rest_framework.auth_token.models import Token
    ...
    
    class NonBuiltInUserToken(Token):
            """
            Overrides the Token model to use the
            non-built-in user model
            """
            user = models.OneToOneField(
                User, related_name='auth_token',
                on_delete=models.CASCADE, 
                verbose_name=_("User")
            )
    
    

    如果我们检查rest_framework.authtoken.models 中的Token 模型,如果rest_framework.authtoken 不存在于settings.INSTALLED_APPS 中,我们将看到Token 类是抽象的。

    class Meta:
            # Work around for a bug in Django:
            # https://code.djangoproject.com/ticket/19422
            #
            # Also see corresponding ticket:
            # https://github.com/encode/django-rest-framework/issues/705
            abstract = 'rest_framework.authtoken' not in settings.INSTALLED_APPS
    

    因此,为了使用此令牌模型,您需要从 settings.INSTALLED_APPS 中删除 rest_framework.authtoken

    现在,您在用户模型中有一个新的非构建令牌模型。您将在信号中使用此模型来创建令牌。

    【讨论】:

    • 谢谢,但现在我得到一个像这样的 FieldError:FieldError:类“NonBuiltInUserToken”中的本地字段“用户”与基类“令牌”中的同名字段发生冲突。
    • 哦,是的!参考stackoverflow.com/a/39278537/6766209。我已经更新了答案。
    • 我复制粘贴了您的解决方案。但我仍然遇到同样的错误。
    • 在浏览了 rest_framework 源代码和其他一些 SO 答案后,我已经更新了答案
    猜你喜欢
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 2018-07-10
    • 2014-06-10
    • 2020-06-27
    • 2017-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多