认证授权基础概念详解
登录成功只回答了一个问题——你是谁;你能不能读这条订单、删这条数据,是另一个问题。本文先划清认证(Authentication)与授权(Authorization)的边界,再完整走一遍 Session-Cookie 与 Token 两套会话流程,重点讲透 OAuth 2.0 授权码模式”先拿 code 再换 token”的两步设计,最后给出 SSO 单点登录的实现思路。
它解决什么问题
HTTP 协议本身是无状态的,服务端无法判断两个请求是否来自同一个已登录的人。认证体系要解决的第一个问题就是:登录一次之后,如何让后续每个请求都”自动证明身份”。
第二个常见混乱是把两件事搅在一起:证明”你是你”(认证),与判断”你能不能干这件事”(授权)。很多越权漏洞的根源,正是只校验了登录态,却漏掉了针对具体资源的授权判断。
再往外还有两类跨系统需求:第三方应用想拿你的微信、GitHub 账号登录,但你绝不能交出密码——这是 OAuth 2.0 解决的委托授权问题;一家企业十几个内部系统,员工不想每个都登一遍——这是 SSO 要解决的体验问题。
核心原理
认证与授权的分野
认证是校验凭据、确认身份的过程,凭据可以是密码、短信验证码、指纹、硬件密钥,发生在所有访问控制之前。授权发生在认证之后:在身份已知的前提下,依据主体、动作、资源(有时还有时间、地点等环境条件)决定这次请求放行还是拒绝。
HTTP 状态码很好地体现了这个次序:401 表示尚未通过有效认证(名字虽叫 Unauthorized,实际语义是 Unauthenticated),403 表示身份已经明确、但没有权限。架构上,认证的产出只是一个”主体(Principal)”,授权模块拿着主体去和资源规则做匹配。两者如果混写在控制器里,会带来大量重复代码,并且极易漏掉对象级的越权校验。
会话的两种载体
登录态需要有一个载体在请求间传递,主流方案只有两条路线:
- Session-Cookie:会话状态存放在服务端,客户端只携带一个无业务含义的 SessionID,服务端按 ID 查状态。
- Token:状态自包含在经过签名的令牌里(典型代表是 JWT),服务端验签即可还原出声明,不必查询集中存储。
后续所有差异——扩展性、撤销能力、体积、安全风险——几乎都是”状态放在哪”这一个选择推导出来的。
深入机制
Session-Cookie 全流程
浏览器 服务器 |
几个工程要点:SessionID 必须用密码学安全的随机数生成,登录成功后要轮换一次,防止会话固定攻击;存放 SessionID 的 Cookie 应打上 HttpOnly(禁止 JS 读取)、Secure(仅 HTTPS 传输)、SameSite(限制跨站携带)三个属性。
水平扩展时 Session 一致性有三种走法:负载均衡做会话保持,把同一用户固定路由到同一节点(节点宕机会话即丢失);节点之间互相同步会话(节点越多同步成本越高,基本弃用);把会话放进 Redis 等集中存储,所有节点共享(当前主流,但要保证存储本身高可用)。
CSRF 与 Token 全流程
Cookie 方案有一个绕不开的攻击面:CSRF(跨站请求伪造)。浏览器对目标域的请求会自动带上 Cookie,攻击者只需诱导用户点一个链接,就能借用户身份发出转账、改密等请求。防御靠 SameSite、CSRF Token、Origin/Referer 校验这一组组合拳。
Token 方案的流程是:登录后服务端签发令牌,客户端自行保存,之后每个请求显式地把它放进 Authorization: Bearer <token> 请求头。因为浏览器不会自动携带这个头,传统 CSRF 的前提不成立——起决定作用的是凭据的携带方式,而不是令牌格式本身。
以 JWT 为例,令牌由 header.payload.signature 三段 Base64URL 组成。签名保证内容不被篡改,但 payload 只是编码而非加密,任何人都能解开看,所以不要放敏感明文。实用搭配是短寿命的 access token 加长寿命的 refresh token,把泄露窗口压到分钟级。真正的软肋是撤销——JWT 签发后在过期前天然有效,要么接受这个窗口,要么引入黑名单/版本号,代价是重新回到查存储。
OAuth 2.0 四种模式
OAuth 2.0 是委托授权的行业标准,目标是让第三方应用在不接触用户密码的前提下,获得有限、有时效的访问权限。涉及四个角色:资源所有者(用户)、客户端(第三方应用)、授权服务器、资源服务器。
授权码模式是安全性最高、应用最广的模式:
1. 客户端把用户浏览器重定向到授权服务器: |
为什么要拆成”先发 code、再换 token”两步?因为这两步走的通道安全性完全不同:
- code 经过浏览器地址栏传递,可能残留在浏览器历史、访问日志、Referer 里,泄露面很大。所以 code 被设计成一次性、几十秒内过期,且与 client_id 和 redirect_uri 绑定。
- token 交换发生在客户端后端与授权服务器之间,
client_secret只存在于服务端。攻击者即使截获 code,没有 secret 也换不出 token;换了回调地址也对不上绑定关系。 state参数用于防回调被调包(授权流程自身的 CSRF 防护),客户端校验回跳时的 state 与发起时一致才继续。
其余三种模式适用面都很窄:**简化模式(Implicit)**直接在前端通道返回 token,泄露面大,OAuth 2.1 已将其移除,纯前端应用改用授权码 + PKCE;密码模式要求用户把账号密码直接交给客户端,仅适用于自家第一方高信任客户端;客户端凭证模式没有用户参与,用于服务间机器对机器调用。
SSO 实现思路
SSO 的目标是:一次登录,一组相互信任的系统都认得你。常见两条路线:
- 同主域共享 Cookie:把登录态 Cookie 种在共同父域(如
.example.com),子域应用都能读到。最简单,但只适用于同一主域。 - 独立认证中心(CAS 思路):子系统发现未登录就重定向到认证中心;认证中心登录成功建立全局会话,携带一次性 ticket 跳回子系统;子系统后端拿 ticket 向认证中心验证后建立局部会话。此后访问其他子系统时认证中心已有全局会话,直接签发 ticket,用户无感。跨域场景都走这条路,OAuth 2.0/OIDC 也可作为 SSO 的协议底座。
单点登出比登录更难:一个系统登出后,需要通知其余系统失效各自的局部会话,做法包括认证中心回调通知、或让局部会话直接共享同一份集中存储。
工程实践
- SessionID、Token 都要高随机且长度足够;登录、提权后轮换会话标识。
- Token 存哪里是经典争论:
localStorage怕 XSS 读取;HttpOnlyCookie 更抗偷取但要补 CSRF 防御;要求高的浏览器应用可用 BFF 模式,把令牌留在后端,前端只持有会话 Cookie。 - 修改密码、支付等敏感操作要求二次认证,不能仅凭一个长期会话放行。
- 用户权限变更后,已签发 JWT 里的旧声明在过期前仍然有效,需要靠缩短有效期、刷新时重查权限来收敛窗口。
- XSS 与认证机制无关:
HttpOnly只能防脚本直接读 Cookie,防不了脚本以用户身份发请求,输出编码与 CSP 仍然是必备防线。
对比与权衡
| 维度 | Session-Cookie | Token(JWT Bearer) |
|---|---|---|
| 会话状态位置 | 服务端集中存储 | 令牌自包含 |
| 水平扩展 | 需共享存储或会话保持 | 验签即可,天然无状态 |
| 主动撤销 | 删 Session 立即生效 | 过期前难撤销,需黑名单兜底 |
| 请求开销 | 每次查一次会话存储 | 本地验签,CPU 换 IO |
| 载荷体积 | Cookie 只有一个 ID | 令牌较长,每个请求都携带 |
| CSRF 风险 | 有,需 SameSite/CSRF Token | 显式 Header 携带,天然规避 |
| 典型场景 | 传统服务端渲染、同源 Web | 前后端分离、多端、开放 API |
面试视角
Cookie 和 Session 有什么区别?客户端禁用 Cookie 怎么办? Cookie 是浏览器侧的存储机制,Session 是服务端的会话概念,二者常被搭配使用但互不绑定。禁用 Cookie 后,可以用约定的请求头显式携带会话标识;不要把 SessionID 拼进 URL,那会泄露出历史记录、日志和 Referer。
JWT 怎么撤销? 首选短 access token 加 refresh token,把泄露窗口压到分钟级;必须立即生效的场景引入黑名单或用户级令牌版本号,但这等于重新引入服务端状态,要在”无状态”和”可撤销”之间明确取舍。
授权码模式为什么不直接发 token,要先发 code? 直接发 token 就必须经过浏览器重定向,泄露面大且无法机密保管;拆两步后 code 短寿、一次性、与客户端绑定,token 由后端持 client_secret 在服务端通道换取,授权服务器还能借此确认回调没有被调包。
用了 Token 就没有 CSRF 了吗? 关键在携带方式:放在 Authorization 头里显式发送,浏览器不会自动附带,传统 CSRF 不成立;但如果又把 Token 存回自动携带的 Cookie,问题原样回归。另外 XSS 与认证机制无关,令牌存哪都防不了恶意脚本冒充用户发请求。
SSO 和 OAuth 是一回事吗? 不是。OAuth 是委托授权协议,解决”不交出密码也能授权第三方”;SSO 是一种登录体验目标。SSO 可以用共享 Cookie、CAS ticket 实现,也可以把 OAuth 2.0/OIDC 当协议底座。
小结
- 认证回答”你是谁”,授权回答”你能做什么”;401 与 403 的分界就是这两件事的分界。
- Session-Cookie 状态在服务端,好撤销但要解决多节点共享;Token 状态自包含,扩展好但撤销弱、体积大。
- Cookie 自动携带带来 CSRF,Token 显式携带规避 CSRF;两者都防不了 XSS,纵深防御不可省。
- OAuth 2.0 授权码模式的核心智慧是通道分离:浏览器通道传一次性 code,服务端通道持 secret 换 token。
- SSO 的本质是”全局会话 + 局部会话”,同域共享 Cookie 最省事,跨域用认证中心或 OIDC;别忘了设计单点登出。

