从请求进来到 request.user 有值,中间发生了什么?authenticate 和 login 各做什么?session 里到底存了什么?这篇用查询捕获和信号,把认证的每一步展开。
匿名、视图没访问 request.user:查询 0
已登录、视图没访问 request.user:查询 0 []
已登录、视图访问 request.user:查询 2
SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expir
SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_supe
→ {'user': 'u', 'auth': True}
匿名(没有 sessionid cookie)访问 request.user:查询 0AuthenticationMiddleware 只是给 request.user 放了一个惰性对象。视图不访问就不会有任何数据库开销;访问时先读 session、再按 id 取用户。
密码错误:返回 None 查询: ['SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_supe'] 信号: [('failed', {'username': 'u', 'password': '********************'})]
密码对:返回 u 信号: []
多余参数 foo=bar:返回 u ← 不同后端接收不同参数,ModelBackend 收下多余的 **kwargs
不带 username/password(别的凭据):返回 None 信号: [('failed', {'token': '********************'})]
is_active=False 的用户密码正确: None (ModelBackend 拒绝不活跃用户)它只负责「凭据 → 用户」,不改变 session。失败信号里的凭据是打过码的(实测:password 与 token 都是 20 个星号,username 保留),所以信号接收者写日志也不会泄露密码。
session 内容的键: ['_auth_user_backend', '_auth_user_hash', '_auth_user_id'] _auth_user_id = 3 _auth_user_backend = django.contrib.auth.backends.ModelBackend _auth_user_hash 长度 = 64 (来自密码哈希的派生值)
下一篇(第 72 篇)看 session 本身怎么存,第 73 篇看 login() 的内部,第 80 篇看这个 hash 的作用。