
django 默认在用户密码变更后自动清除其会话,导致用户登出;解决方法是调用 `update_session_auth_hash()` 保留当前登录状态。
在 Django 中,当用户密码被修改(例如通过自定义视图 psswdReset),框架出于安全考虑会主动使所有基于旧密码哈希的会话失效——这是默认行为,并非 Bug。其原理在于:Django 将用户密码哈希值嵌入 session 数据的认证签名中(通过 SESSION_AUTH_HASH 机制)。一旦 user.password 字段更新,request.user.get_session_auth_hash() 返回值随之改变,而现有 session 中存储的旧 auth hash 不再匹配,中间件(AuthenticationMiddleware)检测到不一致后,便将 request.user 重置为 AnonymousUser,即“会话被冲刷”。
你当前的视图存在两个关键问题:
- 未调用 update_session_auth_hash() → 导致会话立即失效;
- 直接赋值 user.password = make_password(...) 并 .save() → 绕过了 Django 用户模型的密码设置逻辑(如信号触发、密码验证等),且未更新 session 认证哈希。
✅ 正确做法是使用 set_password() 方法(它会自动哈希并触发相关逻辑),并在保存后立即调用 update_session_auth_hash(request):
from django.contrib.auth import update_session_auth_hash
from django.contrib import messages
def psswdReset(request):
if request.method == 'POST':
new_psswd = request.POST.get('new_psswd')
psswd = request.POST.get('psswd')
# 验证旧密码(推荐使用 check_password)
if not check_password(psswd, request.user.password):
messages.error(request, 'Current password is incorrect.')
return render(request, 'User/userPsswdReset.html')
# ✅ 安全设置新密码(自动哈希 + 触发信号)
request.user.set_password(new_psswd)
request.user.save()
# ✅ 关键:更新 session 的认证哈希,保持登录态
update_session_auth_hash(request, request.user)
messages.success(request, 'Password changed successfully!')
return render(request, 'User/userPsswdReset.html')
return render(request, 'User/userPsswdReset.html')⚠️ 注意事项:
- update_session_auth_hash() 必须在 user.save() 之后、响应返回之前调用;
- 不要手动操作 user.password 字段,始终优先使用 set_password();
- 若使用 CustomUser 模型,请确保其继承自 AbstractBaseUser 或 AbstractUser,并正确实现了 set_password;
- 此机制依赖 django.contrib.auth.middleware.AuthenticationMiddleware,请确认已启用。
总结:密码变更触发会话失效是 Django 的内置安全防护,而非异常。只需在修改密码后显式调用 update_session_auth_hash(request, user),即可无缝延续用户会话,兼顾安全性与用户体验。










