认证边界与方案选择
认证建立的是请求与主体之间的可信关联。这个主体可能是个人账号,也可能是服务账号;业务系统仍需要判断账号状态、组织成员资格和资源权限。
OWASP 的认证说明区分了身份认证与身份核实:证明能控制某个账号,并不自动证明其现实身份。手机验证码通常证明此时能接收该号码的消息,实名认证需要额外的证据与业务流程。
六个容易混在一起的对象
| 对象 | 职责 | 不应承担的职责 |
|---|---|---|
账号 user_id | 应用内稳定的主体标识 | 直接充当秘密凭据 |
| 登录标识 | 帮助定位账号,如用户名、邮箱 | 单凭标识判定本人操作 |
| 认证器或凭据 | 提供身份证明,如密码、私钥 | 决定全部业务权限 |
| Session | 维护一次登录后的上下文与有效状态 | 替代资源级授权 |
| Token | 携带或引用某项凭证、授权结果 | 因为名字叫 Token 就被信任 |
| 权限策略 | 判断主体对资源的动作 | 通过隐藏按钮替代后端检查 |
Cookie 是浏览器保存并发送数据的机制;Session 是登录状态模型;JWT 是声明的编码与保护格式。三者不在同一层,可以组合:Cookie 里既能放随机 Session ID,也能放签名令牌。安全特征取决于完整方案。
一次受保护请求的判断链路如下。认证得到主体后,账号、成员和资源权限仍需要按业务要求检查。
状态检查覆盖账号是否可用,以及当前操作所需的组织成员资格;资源授权判断主体能否执行本次动作。令牌的密码学验证通过后,后续检查仍遵守业务要求的状态新鲜度。
三种常见请求链路
服务端 Session
浏览器持有随机会话凭据,服务端查询会话记录,得到账号和认证上下文。账号封禁或退出时修改服务端状态,后续请求读取到新状态就会拒绝访问。
这种方案容易实现设备列表和精确撤销,代价是每次请求的存储或缓存查询。把会话库换成 Redis 只改变存储性能,不会自动解决故障恢复和撤销一致性。具体见 Session 设计。
本地验证 Access Token
API 验证签名和声明后读取主体,不必每次询问签发方。签发方短时不可达时,已缓存密钥的服务仍可能接受未过期令牌。
下图中 API 已持有可信的验证密钥。签名与声明在本地校验,账号状态与权限是否在线查询,由各操作的时效要求决定。
代价是账号状态和权限容易滞后。若要求封禁立即生效,就要增加状态查询、撤销列表或事件传播;此时不能再把整个系统称为“完全无状态”。RFC 7662定义了查询令牌活动状态的 introspection 机制,能集中控制有效性,也增加在线依赖。
浏览器通过 BFF 访问 API
BFF(Backend for Frontend)是专门服务某类前端的后端。浏览器与 BFF 使用 Cookie 会话,BFF 保存上游令牌并调用 API,减少令牌暴露给页面脚本的机会。
以一次状态变更请求为例,浏览器持有本地会话凭据,上游 Access Token 保存在 BFF 服务端。
BFF 增加一次代理、会话存储和扩容成本,也仍需 CSRF 防护、输出编码和请求目标限制。它适合已有后端、且希望统一管理浏览器认证的应用;对于原生移动端,需要另外设计授权码与安全存储流程。
按客户端选择方案
下表是方案评估起点,不是协议对客户端的唯一限制。
| 场景 | 优先评估 | 主要代价 |
|---|---|---|
| 自有同源网站 | 服务端 Session | 在线状态存储与容量 |
| 浏览器调用多个后端 | BFF + 本地会话 | 代理成本、CSRF 与接口边界 |
| 原生移动应用 | 系统浏览器授权码 + PKCE | 回调配置、令牌存储和刷新 |
| 直接访问 API 的 SPA | 授权码 + PKCE,审查浏览器令牌暴露 | XSS、刷新与跨域复杂度 |
| 企业统一登录 | OIDC 或对接企业现有 SAML | 联合身份映射、退出和撤权 |
| 第三方代用户调用 API | OAuth 委托授权 | 客户端、scope、同意与撤销管理 |
原生应用与 SPA 无法可靠保守一个随客户端分发的固定 client_secret,应按公共客户端设计。OAuth 流程与 PKCE 要求见 RFC 9700 §2.1;不能把客户端内置字符串当作服务端身份凭据。
认证上下文比用户 ID 更丰富
敏感操作往往需要知道“最近如何证明过身份”。建议在服务端维护:
| 字段 | 用途 |
|---|---|
user_id、session_id | 主体和本次登录实例 |
authenticated_at | 首次完成认证的时间 |
reauthenticated_at | 最近重新认证的时间 |
auth_methods | 实际通过的密码、OTP、WebAuthn 等方式 |
assurance_policy | 应用内部通过的策略标识 |
security_version | 账号安全变更版本 |
“已使用 MFA”不等于永远可以修改收款账户。业务可要求在短时间内重新认证,并将提升结果绑定到目标操作。外部 OIDC 的 acr、amr 值还需要与提供方约定含义,不能直接把任意字符串解释成满足本地高强度策略。
用户身份与服务身份
定时任务、服务间调用和自动化客户端应使用独立机器身份,避免保存员工密码来模拟登录。服务可以代表自己,也可以在明确授权的链路中代表用户;两者要分别记录,以免审计中只有一个无法解释的 user_id。
网关传入的用户头只有在下游无法被外部直接访问、网关清除了外来同名头、内部连接受保护时才可信。是否经过网关不能由客户端自己提供一个布尔字段证明。
自建与接入身份提供方
成熟身份提供方可以承担协议、密钥、认证器与联合登录。应用仍需维护账号与外部身份映射、业务状态、租户成员和资源权限。
选择时应实际验证:导出和迁移能力、账号恢复、单点退出、租户隔离、审计事件、灾备与不可用时的行为。托管服务减少的是实现与运维工作,同时引入外部依赖;自建则需要持续承担协议升级和安全修复。
参考资料
- OWASP:Authentication Cheat Sheet
- IETF:RFC 7662 — OAuth 2.0 Token Introspection
- IETF:RFC 9700 §2.1 — Redirect-Based Flows
工程实践与社区文章
- 美团技术团队:百亿规模API网关服务Shepherd的设计与实现——网关鉴权、流量控制与通用能力的组件化设计。