想支持邮箱登录、token 登录,就要写认证后端。它们的调用顺序是什么?怎么被 login 记住?后端改了配置会发生什么?这篇写三个后端并打日志,把这些行为一一验证。
username/password 登录 → u 调用日志: ['TokenBackend.authenticate(token=None)', "ModelBackend.authenticate(username='u')"] 用邮箱 → u 调用日志: ['TokenBackend.authenticate(token=None)', "ModelBackend.authenticate(username='u@x.com')", "EmailBackend.authenticate(username='u@x.com')"] token=good → tok 调用日志: ["TokenBackend.authenticate(token='good')"] 密码错 → None 调用日志: ['TokenBackend.authenticate(token=None)', "ModelBackend.authenticate(username='u')", "EmailBackend.authenticate(username='u')"]
后端的 authenticate 通常用关键字参数接收凭据(username/password、token…),Django 会跳过签名不匹配的后端(本文的日志里 TokenBackend 收到 token=None 就是这个机制的结果)。
token=banned → None 调用日志: ["TokenBackend.authenticate(token='banned')"]
用于「这个用户被明确禁止,不要再问别的后端了」。
直接 login(user)(没有 backend 属性、没有 backend 参数): ValueError: You have multiple authentication backends configured and therefore must provide the `backend` argument or set the `backe authenticate 返回的 user.backend = proj.be.LoggingModelBackend session[_auth_user_backend] = proj.be.LoggingModelBackend 显式 backend 参数: proj.be.EmailBackend
只有一个后端时可以省略;多个后端时缺 backend 直接报错。
get_user(request) → u (通过 session 里记录的后端 ModelBackend.get_user) 把 session 里的后端改成 TokenBackend 后 get_user → u (该后端的 get_user 也能取到,session hash 仍校验) AnonymousUser
上线时改 AUTHENTICATION_BACKENDS(比如移除旧后端),所有 session 里记着旧后端的用户会被静默登出,且没有任何错误日志。改之前要评估影响。