bigywater.tech
Django · 73

login()、logout() 的内部过程

login() 和 logout() 到底对 session 做了什么?key 会变吗?数据保留吗?这篇分四种情形逐一验证,并列出登录时发出的 SQL。

cycle_key
匿名 → 登录:session_key 换新、数据保留、旧行删除
flush
换用户登录或 logout:清空整个 session(行删除、数据没了)
last_login
login() 顺带 UPDATE 用户的 last_login,是登录路径上的一次额外写

登录:cycle_key

实测 · 本机执行输出
登录前 key = e217w0dz…  登录后 key = zkdqab8x…  key 变了: True  cart 保留: [1, 2]
session 表现在的 key: ['zkdqab8x…']  (老 key 已删除: True )
登录发出的 SQL:
    SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser
    SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_dat
    SELECT 1 AS "a" FROM "django_session" WHERE "django_session"."session_key" = 'zkdqab8xrsevi516dphy80
    BEGIN
    INSERT INTO "django_session" ("session_key", "session_data", "expire_date") VALUES ('zkdqab8xrsevi51
    COMMIT
    SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_dat
    DELETE FROM "django_session" WHERE "django_session"."session_key" IN ('e217w0dzy0rx3rxsuoxyo9jjmp2vl
    UPDATE "auth_user" SET "last_login" = '2026-09-30 12:42:23.325834' WHERE "auth_user"."id" = 1
    BEGIN
    UPDATE "django_session" SET "session_data" = '.eJxVzDsOgzAQBNC7bI0svBiDKdNzgihC6_U6kERY4lNFuXuMREM7b
    COMMIT

购物车保留是有意的:用户在登录前加入购物车,登录后不应丢失。但 session id 必须换,防止会话固定攻击。

换用户与同用户

实测 · 本机执行输出
u → v:cart = None  key 变了: True
v → v(同一用户再登录):cart 与 key: None True

规则:session 里已有另一个用户 id → flush;已有同一个用户 → 只是沿用。

登出

实测 · 本机执行输出
登出前 session 行数 = 1  登出后 = 0  登出后 cart = None  key 变了: True
SQL:
    SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_dat
    SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser
    SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_dat
    DELETE FROM "django_session" WHERE "django_session"."session_key" IN ('1ipwu7hlipdb6yntb3dkxvodu1glx
用旧 cookie 之外的新会话重新访问 /cart/: x322x0kk…

logout() 会 session.flush(),所以登出前放在 session 里的其他数据(如语言偏好)也没了——想保留的要在登出后重新写。

last_login

实测 · 本机执行输出
登录前 last_login = None
登录后 last_login = 2026-09-30 12:42:25
断开 update_last_login 之后登录 v:last_login = None

信号 user_logged_in 的默认接收者是 update_last_login。

分步演示:登录与登出

login / logout
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。SQLite;session 行数用 Session.objects.count() 统计
    • 没有验证:SESSION_SAVE_EVERY_REQUEST 下的登录、多个标签页并发登录、logout 与 CSRF token 轮换的关系(第 70 篇只看到登出前后 cookie 不变)、异步 alogin
    京ICP备2026067502号-1京公网安备11010502063487号