bigywater.tech
Django · 80

密码修改后为什么会让其他设备下线

用户在手机上改了密码,电脑上的登录为什么立刻失效?为什么改密码的这台设备自己也被登出了?Django 是怎么做到的?这篇用两个「设备」把机制和例外都跑一遍。

hash 比对
session 里存了由密码哈希派生的 _auth_user_hash,每个请求与用户表重新比对
含当前设备
改密码后不调用 update_session_auth_hash,发起修改的那台设备也被登出
重新哈希
同一个明文重新哈希(盐变了)也会让所有会话失效

hash 从哪来

实测 · 本机执行输出
session 里的 hash = 5696a8ff42b8ccb1…  用户密码哈希 = pbkdf2_sha256$1500000$17…
u.get_session_auth_hash() 与 session 里一致: True
改密码后 get_session_auth_hash() 与旧 session 里的一致: False

密码哈希变了,派生出来的 session hash 就变了。这也是 SESSION_ENGINE = signed_cookies 时仍能「登出所有设备」的原因(第 79 篇)。

两台设备

实测 · 本机执行输出
改密码前 A: {'user': 'u'}  B: {'user': 'u'}
A 上改密码(不调用 update_session_auth_hash)之后 A: {'user': 'AnonymousUser'}  B: {'user': 'AnonymousUser'}
A 上改密码并调用 update_session_auth_hash(request, user) 之后 A: {'user': 'u'}  B: {'user': 'AnonymousUser'}
实测 · 本机执行输出
一个已登录请求的查询: 2 次(session + user);校验 hash 不额外查询

Django 自带的 PasswordChangeView 内部会调用 update_session_auth_hash;自己写改密码视图时一定别忘。

每个请求怎么校验

实测 · 本机执行输出
只改 last_login 之后: {'user': 'u'}
重新哈希同一个密码(盐不同)之后: {'user': 'AnonymousUser'}

校验用的是用户对象里已经取出的密码哈希,不需要额外查询。

登出所有设备

实测 · 本机执行输出
删除了 2 个 session;A: {'user': 'AnonymousUser'}  B: {'user': 'AnonymousUser'}

删除 session 行只适用于数据库(或缓存)后端;cookie 后端要靠让 hash 变化。

分步演示:改密码之后

改密码与会话
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。SQLite;两个 Client 代表两台设备
    • 没有验证:SECRET_KEY_FALLBACKS 轮换对 session hash 的影响、PasswordChangeView / PasswordResetView 的完整流程、单点登录场景、记住我(持久 cookie)的设备
    京ICP备2026067502号-1京公网安备11010502063487号