You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django扩展User类角色冲突及讲师账号密码锁定问题求助

问题解决与代码优化

一、超级用户角色冲突问题

当前自定义User类中,超级用户(is_superuser=True)可能被标记为Alumni角色,导致权限逻辑混乱,可通过以下方式解决:

1. 自动绑定超级用户与Admin角色

在save方法中添加逻辑,当用户被设置为超级用户时,自动将其角色设为Admin,避免手动配置错误:

def save(self, *args, **kwargs):
    # 超级用户自动关联Admin角色
    if self.is_superuser:
        self.role = User.Role.ADMIN
    # 讲师默认密码逻辑保留
    if self.role == User.Role.LECTURER and not self.password: 
        self.set_password('ou@123')
    super().save(*args, **kwargs)

2. 后台Admin防误操作优化(可选)

在Admin管理界面中,禁用超级用户的角色编辑权限,防止手动修改导致冲突:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User

class CustomUserAdmin(UserAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super().get_form(request, obj, **kwargs)
        # 超级用户的角色字段设为不可编辑
        if obj and obj.is_superuser:
            form.base_fields['role'].disabled = True
        return form

admin.site.register(User, CustomUserAdmin)

二、讲师账号密码过期锁定功能优化

原代码存在两个核心问题:仅依赖date_joined无法区分用户是否修改过密码;无自动触发检查的时机。以下是优化方案:

1. 添加密码更新时间字段

在User类中新增password_updated字段,记录最后一次修改密码的时间:

from django.utils import timezone

class User(AbstractUser):
    # 原有字段保留...
    password_updated = models.DateTimeField(null=True, blank=True)

    def save(self, *args, **kwargs):
        # 超级用户角色绑定逻辑
        if self.is_superuser:
            self.role = User.Role.ADMIN
        # 讲师创建时设置默认密码并记录更新时间
        if self.role == User.Role.LECTURER and not self.password: 
            self.set_password('ou@123')
            self.password_updated = timezone.now()
        # 密码变更时更新记录时间
        if self.pk:
            old_user = User.objects.get(pk=self.pk)
            if old_user.password != self.password:
                self.password_updated = timezone.now()
        super().save(*args, **kwargs)

2. 完善密码过期检查逻辑

修改check_password_expiry方法,仅在讲师未修改过密码且超过24小时的情况下锁定账号:

def check_password_expiry(self):
    if self.role != User.Role.LECTURER:
        return
    # 未修改过密码且超过24小时则锁定
    if self.password_updated and (timezone.now() - self.password_updated) > timedelta(hours=24):
        self.is_active = False
        self.save()

3. 设置登录触发检查

通过DRF自定义认证类,在用户登录时自动执行密码过期检查:

from rest_framework.authentication import TokenAuthentication
from rest_framework import exceptions

class CustomTokenAuthentication(TokenAuthentication):
    def authenticate_credentials(self, key):
        user, token = super().authenticate_credentials(key)
        # 登录时检查密码过期状态
        user.check_password_expiry()
        if not user.is_active:
            raise exceptions.AuthenticationFailed("账号已锁定,请联系管理员启用")
        return (user, token)

在settings.py中配置DRF认证:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'your_app_name.authentication.CustomTokenAuthentication',
        # 其他认证类保留...
    ]
}

4. 管理员重新启用账号逻辑

管理员在后台启用讲师账号时,自动重置默认密码并更新时间:

class CustomUserAdmin(UserAdmin):
    # 原有代码保留...
    def save_model(self, request, obj, form, change):
        # 启用讲师账号时重置默认密码
        if obj.role == User.Role.LECTURER and 'is_active' in form.changed_data and obj.is_active:
            obj.set_password('ou@123')
            obj.password_updated = timezone.now()
        super().save_model(request, obj, form, change)

内容的提问来源于stack exchange,提问作者Trần Lệ Lân

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 22:27:48