CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
OAuth 2.0 与 OpenID Connect/课时/OAuth 是什么
RawBlame
课时目录12 节

OAuth 2.0 与 OpenID Connect

  1. 01OAuth 是什么
  2. 02授权码流
  3. 03PKCE 与 SPA
  4. 04OpenID Connect
  5. 05Scope 与权限
  6. 06Refresh Token
  7. 07Spring OAuth2 Client
  8. 08Resource Server
  9. 09第三方登录
  10. 10OAuth vs 本站 JWT 登录
  11. 11常见安全问题
  12. 12综合练习

OAuth 是什么

授权 vs 认证;与 JWT 登录的分工。

30 分钟

OAuth 是什么

这一课你将能做到

  1. 用自己的话说清 认证(Authentication,你是谁) 与 授权(Authorization,你被允许做什么) 的区别,并指出「用 GitHub 登录」同时触发了这两件事
  2. 画出 OAuth 2.0 四角色图(Resource Owner / Client / Authorization Server / Resource Server),把浏览器、你的 Spring 后端、GitHub 准确归位
  3. 用 curl 模拟「不带 token / 带假 token」访问受保护 API,说清 401 与 403 在 OAuth 语境下的语义差别

为什么要学

先看一个每天都在发生的需求:产品经理走过来,「给我们网站加一个『用 GitHub 登录』的按钮」。你面前的路有三条:

  • 反模式:在自家页面放表单,让用户把 GitHub 的账号密码填进来,你替他去登。这等于让用户把银行密码交给前台代管——任何一方泄露都是灾难,用户也不傻,不敢填。
  • 标准答案:把用户带到 GitHub 的页面完成登录与授权,GitHub 回给你一张「通行证」,你再凭它去取用户资料。这就是 OAuth 2.0。
  • 厂商私有方案:早期微信、QQ 有各自的登录 SDK,思想类似但细节私有;如今主流平台基本对齐 OAuth 2.0 / OIDC。

人话版:OAuth 解决的问题是——让应用 A 代表用户去访问应用 B 里的资源,但全程不需要用户把 B 的密码交给 A。

和面试的关系:「OAuth 四种授权模式的差异」「为什么授权码流最安全」「PKCE 解决什么」是后端与全栈面试的高频题。这一课先把角色与全局图建立起来,后面 11 课的细节才不会变成名词堆砌。

和本站的关系:本站登录用的是自研 JWT 方案——用户提交账号密码,backend 校验后签发 JWT,前端带着这个 token 调 /admin/** 等接口。这套方案管「本站认人」;OAuth 管的是「别站认人 / 对外开放授权」。两条轨并存、各管一段,本 track 讲的就是第二条轨。

先建立图像

把 OAuth 想成酒店房卡系统:

房客(Resource Owner,资源的主人 = 用户)
  │ 在前台出示身份证,同意「保洁可以在 14:00-15:00 进房间」
  ▼
前台(Authorization Server,授权服务器,如 GitHub)
  │ 发给保洁一张「限时、限用途」的房卡(access_token)
  ▼
保洁 App(Client,你的应用)
  │ 拿房卡开门,全程没碰过房客的身份证原件
  ▼
房门门锁(Resource Server,资源服务器,如 api.github.com)
      验卡:有效吗?时段对吗?用途对吗?→ 开门或拒绝
角色一句人话现实中的例子
Resource Owner资源真正的主人用户本人
Client想代表用户办事的第三方应用你的网站、你的 App
Authorization Server验证用户并签发通行证的服务GitHub、Google、微信开放平台
Resource Server真正存数据、提供 API 的服务api.github.com、你自己的 /api/v1/**

一次完整授权的时序(先看懂箭头,下一课再逐个拆参数):

浏览器                你的后端(Client)        授权服务器(AS)        资源服务器(RS)
   │ ①点「GitHub登录」       │                     │                   │
   │ ─────────────────────► │  ②302 跳授权页       │                   │
   │ ◄────────────────────────────────────────────│                   │
   │ ③用户在 GitHub 登录并点「同意」                │                   │
   │ ◄──── 302 回 callback,带一次性 code ─────────│                   │
   │ ④GET /oauth/callback?code&state             │                   │
   │ ─────────────────────► │                     │                   │
   │                        │ ⑤code+secret 换 token│                   │
   │                        │ ───────────────────►│                   │
   │                        │ ◄── access_token ────│                   │
   │                        │ ⑥Bearer token 调 API│                   │
   │                        │ ──────────────────────────────────────► │
   │                        │ ◄───────────── 用户资料 ──────────────── │

两个关键事实:用户的 GitHub 密码只出现在 GitHub 的页面上;access_token 从头到尾没在浏览器地址栏出现过。

跟着做

步骤 1:拆一次「用 GitHub 登录」,填四角色

不写代码,打开笔记回答四个问题:

1. 用户点击按钮后,浏览器被带去了哪里? → GitHub 的授权页(Authorization Server)
2. 用户点「同意」后,浏览器被带回了哪里? → 你在 GitHub 后台预登记的 redirect_uri(Client)
3. 谁拿着 code 去换 access_token? → 你的后端(Client 的服务器端)
4. 谁最终返回用户的 id 和头像? → GitHub 的 API(Resource Server)

步骤 2:用 curl 建立「资源服务器只认 token」的直觉

# 不带任何 token,请求 GitHub 受保护接口 → 401
curl -i https://api.github.com/user

# 带一个假 token → 仍是 401
curl -i https://api.github.com/user \
  -H "Authorization: Bearer ghp_this_is_fake_token"

观察响应头里的 WWW-Authenticate: Bearer。建立直觉:资源服务器不认识你浏览器里的 cookie,它只认请求头里的 Authorization: Bearer <token>。

步骤 3:在浏览器里亲眼看一次授权页

直接访问(登录与否都行):

https://github.com/login/oauth/authorize?client_id=某公开应用的client_id

你会看到 GitHub 的授权页面。这就是授权流程的第一跳——浏览器整页跳转,不是 AJAX。URL 里的 client_id 告诉 GitHub 是哪个应用在申请。

步骤 4:对照本站,写出两条轨

本站密码登录(认证轨):
  用户名+密码 → POST /auth/login → backend 校验 → 签发本站 JWT → Bearer 调受保护接口

联邦登录(OAuth 轨,本 track 主题):
  用户在 GitHub 登录并同意 → 你的后端拿 code 换 token → 拉到用户身份
  → 本站 User 表 findOrCreate → backend 签发本站 JWT → 后续与密码登录完全一样

关键结论:OAuth 认完人之后,本站仍然发自己的 JWT。GitHub 的 access_token 只用来调 GitHub 的 API,不会变成你站内接口的钥匙。

步骤 5:把三个英文词各翻译成一句中文

Authentication —— 证明「你是张三」
Authorization  —— 证明「张三同意这个 App 读他的资料」
Delegation     —— 张三把「读资料」委托给了 App,但密码没给

讲清楚要点

  1. OAuth 2.0 是授权框架,不是登录协议。它回答「App 能否访问资源」,不规定「如何证明眼前这人是谁」。产品上的「第三方登录」通常是 OAuth + OIDC(第 4 课)或 OAuth + 用户信息 API 的组合。
  2. 用户密码绝不过 Client 的手。整个协议的设计目标就是消灭「密码反模式」:密码只出现在 Authorization Server 的页面上。
  3. token 有两种典型形态:不透明字符串(资源服务器需回问授权服务器才懂)和 JWT(自包含、可验签)。本站自研 JWT 属于后者,OAuth 场景的 access_token 也经常是 JWT——但「是 JWT」不等于「是 OAuth」,协议步骤才是 OAuth。
  4. 四角色缺一不可。排错的第一问永远是「卡在哪个角色」:授权页打不开是 AS 的事,callback 404 是 redirect_uri 的事,换 token 失败是 code/secret 的事,调 API 401 是 RS 的事。
  5. Client 分机密客户端(confidential)与公共客户端(public)。有后端、能保管 client_secret 的是前者;SPA、原生 App 藏不住 secret,属于后者,必须用 PKCE(第 3 课)。
  6. 本站自研 JWT 与 OAuth 不冲突。密码轨和联邦轨最终都汇聚到「backend 签发本站 JWT」,站内权限模型不用因为引入 OAuth 而重写。

你可能会懵的地方

  • 「OAuth」这个词里的 Auth 到底是认证还是授权? 是授权(Authorization)。这是面试常挖的坑:OAuth 全名 Open Authorization,解决「代用户访问资源」;标准化的「认证」由 OIDC 补齐。

  • access_token 和本站 JWT 是一个东西吗? 格式上可能都是 JWT,但发行方、受众、校验方式完全不同。本站 JWT 由 backend 用自己的密钥签发、给本站接口用;GitHub 的 access_token 由 GitHub 签发、给 GitHub 的 API 用。互不通用。

  • 为什么不让前端直接和 GitHub 交互拿 token? 机密客户端的 client_secret 不能进前端;SPA 没有后端也要走 PKCE 授权码流。在前端拼 secret 是高危错误。

  • Resource Owner 和 Resource Server 名字像,怎么记? Owner 是人,Server 是机器。房客 vs 门锁。

  • 微信登录是 OAuth 吗? 思想同源(跳转授权、code 换 token),但细节是微信自己的私有实现(如网页授权的 snsapi_userinfo)。学透标准 OAuth 后,看厂商文档会非常快。

错法对照

错法问题正解
自建表单收集用户在第三方平台的密码密码泄露即灾难,用户也不会信任跳转到 IdP 授权页,Client 只接收 code/token
以为「OAuth 就是发个 JWT 当登录态」混淆协议与 token 格式,设计必然走偏先分清协议步骤与 token 形态,JWT 只是常见载体
把 GitHub 的 access_token 直接拿来调本站 /admin发行方不同,本站无法验签,等于裸奔映射本地用户后,由 backend 签发本站 JWT
四角色图只画「前端和数据库」漏掉 AS/RS 后所有排错都找不到方向任何 OAuth 讨论先摆出四角色
把 scope 授权(OAuth)与站内角色(RBAC)混为一谈语义不同,权限模型会乱OAuth 管「用户对 App 的授权」,RBAC 管「站内用户能做什么」

卡点急救

  1. 现象:觉得 OAuth 概念太多,不知道从哪开始。先把四角色图默画三遍,再用本课的 GitHub authorize URL 亲眼看一次授权页。后续所有细节都挂在这张图上加箭头。
  2. 现象:分不清 401 和 403 该查什么。401 = 没带 token 或 token 无效/过期,查「凭证链」;403 = token 有效但权限不够,查「scope/角色」。本站接口同理。
  3. 现象:资料里一会儿说 access_token 是 JWT,一会儿说是不透明串,懵了。两种都合法,取决于授权服务器的实现。GitHub 发的是不透明串,很多企业 IdP 发 JWT。遇到具体平台,查文档确认形态。

面试常问

  • OAuth 2.0 有哪四种授权模式(grant type)? 授权码模式(Authorization Code)、隐式模式(Implicit,已废弃)、密码模式(Resource Owner Password Credentials,已不建议)、客户端凭据模式(Client Credentials,用于纯机器对机器)。另有 PKCE 扩展与设备码模式(Device Flow)。答题时点出「授权码是主路,Implicit 与密码模式因安全原因被 OAuth 2.1 淘汰」是加分项。

  • 为什么说授权码模式最安全? 它把「浏览器经手的东西」压缩到一枚一次性、短寿命的 authorization code;真正的 access_token 只在 Client 后端与授权服务器之间的服务端信道交换,不出现在 URL、历史记录、Referer 中;再叠加 state 防 CSRF、PKCE 防 code 拦截,攻击面最小。

  • 你们站为什么自研 JWT 而不直接上 OAuth? 因为只有自己家的前端在登录,没有第三方应用接入、也没开放 API,引入 OAuth 属于过度设计;自研 JWT(backend 签发、验签)简单可控。当出现「用 GitHub/Google 登录」或「第三方开发者调我们的 API」的需求时,再按本 track 引入 OAuth,且最终仍发本站 JWT 管会话。

自测三问

  1. 认证与授权各回答什么问题?「用 Google 登录」主要解决哪个、顺带解决哪个?
  2. 默写 OAuth 四角色,并给每个角色找一个现实系统对号入座。
  3. 本站密码登录和 GitHub 联邦登录,最终的会话凭证分别是谁签发的?

小结一句话

OAuth 2.0 = 让用户授权第三方应用访问资源、全程不交密码的框架;认清四角色与两条轨(站内 JWT / 联邦 OAuth),后面所有细节都挂在这张图上。

延伸

  • OAuth 2.0 官方站点
  • RFC 6749:The OAuth 2.0 Authorization Framework
  • 下一课:授权码流——把本课时序图拆成五个带参数的 HTTP 请求,并解释为什么它是最安全的模式。
加载本节练习…
下一课 →授权码流