在 Django Rest Framework 中处理 JWT 身份验证和软删除用户

Handling JWT Authentication and Soft Deleted Users in Django Rest Framework

我正在尝试让用户名在用户删除帐户后可用。默认情况下,用户名是唯一的,这意味着即使帐户被软删除,用户名也将不可用。

默认情况下,这是开箱即用的 django 设置。

class CustomUser(AbstractUser):
    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[UnicodeUsernameValidator()],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )

is_active 用于将模型标记为已删除。

为了能够利用 UniqueConstraint 并添加条件,我必须放弃用户名的唯一性。

class CustomUser(AbstractUser):
    username = models.CharField(
        _('username'),
        max_length=150,
        unique=False,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[UnicodeUsernameValidator()],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['username'],
                name='active_username_constraint',
                condition=models.Q(is_active=True)
            )
        ]

这适用于注册。用户删除帐户后,可以在注册期间重新使用用户名。但是,当用户登录时,会出现以下错误。

MultipleObjectsReturned at /api/vdev/login/
get() returned more than one CustomUser -- it returned 2!

我正在尝试找出一种方法来检查用户是否 is_active 作为身份验证过程的一部分。有什么办法可以做到吗?

我猜当从 UserModel 调用 authenticate 时会引发错误。查看此方法的 source code, the method calls get_by_natural_key from the user manager. Examining the source code 向我们展示了我们需要进行更改的地方。

因此,您可能要做的是创建自定义用户管理器,继承自 BaseUserManager 并覆盖 get_by_natural_key.

class MyUserManager(BaseUserManager):
    ...
    def get_by_natural_key(self, username):
        return self.get(**{self.model.USERNAME_FIELD: username, "is_active": True})

然后在您的自定义用户模型中,将您的管理员设置为此自定义用户管理员:

class CustomUser(AbstractUser):
    ...
    objects = MyUserManager()