使用django 1.11+DRF时createsuperuser生成密码错误问题求助
createsuperuser生成无效密码的几种情况 这种情况我之前在Django 1.11项目里也碰到过几次,结合这个版本的特性和常见的开发坑,大概率是下面这些原因导致的:
自定义User模型的密码处理逻辑错误
如果你项目里用了自定义的AbstractBaseUser或AbstractUser,却没有正确继承密码相关的方法,或者在模型的save()方法里手动修改了password字段而没有调用set_password(),就会搞砸createsuperuser生成的密码哈希。因为createsuperuser内部是通过set_password()生成标准的BCrypt/PBKDF2哈希,但如果你的自定义逻辑覆盖了这个过程(比如直接给password赋值明文或错误的哈希),登录时自然验证失败。而changepassword命令是严格调用set_password()后保存的,所以能正常生效。Post-save信号篡改了密码
如果你的项目注册了针对User模型的post_save信号,并且在信号处理函数中不小心修改了用户密码(比如误重新设置了密码、重复哈希了密码),那createsuperuser刚创建好用户,信号就把正确的哈希值覆盖成错误的了,导致登录失败。而changepassword修改密码时,要么信号没触发,要么触发后的逻辑是正确的,所以密码能正常存储。自定义认证后端的逻辑问题
如果你在AUTHENTICATION_BACKENDS里配置了自定义的认证后端,后端的authenticate()方法可能没有正确使用Django自带的check_password()函数来验证密码。比如有的开发者会手动对比哈希值,却用了和Django默认不同的哈希算法,导致createsuperuser生成的标准哈希无法被验证,但changepassword生成的哈希刚好符合后端逻辑(不过这种情况相对少见,更多是后端逻辑和默认哈希不兼容)。数据库字段配置错误
要是你的User模型password字段的max_length设置得太短(Django 1.11默认是128位,哈希值一般是60位左右),或者数据库字段的字符集不是UTF-8,就可能导致哈希值被截断或乱码存储。createsuperuser写入的完整哈希被破坏,而changepassword生成的哈希可能刚好能被正确存储,或者数据库字段类型错误(比如用了TEXT而非VARCHAR)也可能引发这类问题。Django 1.11版本的特定bug
虽然概率不高,但某些旧版本的Django 1.11在处理包含特殊字符(比如中文、emoji、复杂符号组合)的密码时,createsuperuser命令可能存在哈希生成错误的问题。你可以试试创建一个纯字母数字的超级用户,如果能正常登录,那大概率是特殊字符的锅。
排查建议
可以按照这个顺序快速定位问题:
- 检查自定义User模型的
save()方法和继承关系,确保没有手动修改password字段,所有密码设置都通过set_password()完成。 - 查看项目中的信号处理函数,特别是针对User模型的
post_save信号,有没有修改密码的逻辑。 - 暂时注释掉自定义认证后端,用默认的
ModelBackend测试登录,看是否正常。 - 检查数据库中User表的password字段长度和字符集配置,确保符合Django的要求。
- 尝试创建一个纯字母数字的超级用户,验证是否能登录。
内容的提问来源于stack exchange,提问作者Dr.Dean

