Django自定义用户模型如何创建无密码超级用户
Django自定义用户模型无密码问题解决方案
核心问题成因
首先明确一个初学者很容易踩的误区:你没有在自定义User类里写password字段,不代表这个字段不存在。
- 你继承的
AbstractBaseUser是Django auth模块内置的基类,已经强制内置了password字段(用于存储哈希加密后的密码),无论你是否显式声明,数据库的用户表都会存在这个字段。 - 内置的
createsuperuser命令默认会读取AbstractBaseUser的字段定义,强制要求输入密码;admin后台的默认登录逻辑也会校验password字段的哈希值,你在create_superuser里没有给这个字段赋值,存的是空值,自然会被判定为密码错误无法登录。
方案评估与落地
你提到的两种思路都可以实现,但是适用场景和维护成本差异很大:
方案1:保留内置password字段,仅超级用户设置密码、普通用户字段置空(强烈推荐)
这个方案完全合理,也是Django生态下的通用实践,不需要修改框架底层逻辑,不会和内置的admin、权限、session、CSRF校验等组件产生冲突,踩坑概率极低。
落地操作步骤:
- 修复
create_superuser方法,正确接收并存储密码:Django不允许明文存储密码,必须调用set_password()方法做哈希加密,修改后的代码示例:
def create_superuser(self, username, email, password=None, **extra_fields): if not password: raise ValueError("Superuser account must set a password") # 先创建关联的店铺 shop = Shop.objects.create(name="openformat") user = self.model( email=self.normalize_email(email), username=username, shop=shop, is_superuser=True, total_points=0, used_points=0, is_staff=True, **extra_fields ) # 哈希加密后存储密码 user.set_password(password) user.save(using=self._db) return user
- 普通用户创建时不需要调用
set_password(),让password字段保持空字符串即可,完全不影响你后续给普通用户实现手机号验证码登录、单点登录、扫码登录等无密码登录逻辑。 - 如果不希望普通用户的admin编辑页显示密码相关操作,可以自定义
UserAdmin类,重写字段集配置,对非超管账号隐藏密码设置入口。
方案2:实现完全无密码的超级用户(仅可用于本地隔离测试环境,生产环境禁用)
如果你一定要让超级用户也不设置密码,理论上可以实现,但需要重写框架默认逻辑,安全风险极高,维护成本也高:
- 第一步:自定义
createsuperuser管理命令,覆盖默认逻辑,移除密码输入的交互步骤,创建超管时直接给password字段设置UNUSABLE_PASSWORD标记(Django内置的不可用密码标识)。 - 第二步:自定义认证后端,继承
ModelBackend重写authenticate方法,针对超级用户账号跳过密码校验逻辑。注意:这个逻辑只要匹配到超级用户名就会直接放行,任何人只要知道超管用户名就能登录后台,生产环境用等于裸奔。 - 第三步:在项目
settings.py里替换默认的认证后端配置:
AUTHENTICATION_BACKENDS = [ "your_app.auth_backends.NoPasswordSuperuserBackend", "django.contrib.auth.backends.ModelBackend", ]
现有代码的其他问题修正
- 你当前的
_create_user方法参数设计不合理:is_superuser、is_staff属于高权限标记,不应该作为普通用户创建的必填位置参数,应该放到**extra_fields中,默认值设为False,避免误创建权限异常的账号。 get_absolute_url方法存在类型错误:uid是UUID类型,不能用%i整数占位符拼接,需要先转成字符串,正确写法是return f"/users/{self.uid}/"。- 如果普通用户走无密码登录通道,记得在登录校验逻辑里主动排除超级用户账号,避免超管账号被无密码入口绕过校验。
内容的提问来源于stack exchange,提问作者user14596364
相关产品推荐
相关产品推荐

