十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OAuth 2.0授权码模式详解:从核心概念到安全实践

OAuth 2.0授权码模式详解:从核心概念到安全实践 我在日常开发里被问得最多的一个问题就是“OAuth 2.0 到底是什么”。问的人从刚转行的前端到写了几年后端的都有大家对这四个词的印象往往停留在“登录的时候弹个 GitHub 授权框”或者“拿 Token 调接口”但真要解释清楚它解决了什么问题、授权码模式为什么是四个模式里的王牌很多人是模糊的。这很正常。OAuth 2.0 是个授权框架不是一套具体的 API也不是一个库它定义的是“怎么把资源的访问权限安全地交给第三方应用”这件事的规则。你可以把它理解成酒店的门卡系统——前台验证你的身份后给你一张只能开特定楼层、特定时间有效的门卡而不是直接把万能钥匙交给你。这个思路贯穿整个协议搞懂了这一点后面的所有概念都能串起来。这篇文章我会把 OAuth 2.0 从零拆开讲先看它解决什么痛点再梳理四个角色和四种授权模式接着重点拆解授权码模式的完整流程然后聊 Token 的设计逻辑最后把我在实际对接中踩过的坑和排查思路一并整理出来。无论你是刚接触 OAuth 的新手还是对接过但总有些细节没想通的开发者这篇应该都能给你一些参考。1. 内容整体设计与思路拆解1.1 OAuth 2.0 到底是什么从“账密共享”到“授权委托”要理解 OAuth 2.0最好的切入点是先看看没有它的时候第三方应用是怎么拿用户数据的。很早之前一个第三方网站如果想让用户导入邮箱联系人最粗暴的做法是让用户把邮箱账号和密码直接交出来。这种模式最大的问题在于你把万能钥匙给了别人对方能看你的邮件、能删你的邮件、能改你的密码——你完全无法限制它只能做某一件事。而且一旦这个第三方网站的数据库被拖库你的邮箱密码也就跟着泄露了连带你的主邮箱可能都被撞库。OAuth 2.0 的诞生就是为了解决这个“过度授权”的问题。它的核心思想是“委托授权”也就是用户本人在授权服务器上确认“我允许这个应用读取我的联系人列表”然后授权服务器发给第三方应用一个访问令牌Access Token这个令牌有过期时间、有权限范围而且只针对某一个资源服务器有效。第三方应用拿着这个令牌去换数据全程不需要看到用户的密码。类比来说这就是酒店前台的做法。你去住酒店前台确认你的预订信息后给你一张房卡房卡只能开你自己的房间而且退房后自动失效。你不需要把酒店的总控钥匙交给任何人服务员打扫房间用的也是单独的员工卡权限是分级的。OAuth 2.0 就是这套门禁系统的协议化。1.2 为什么用授权码模式而不是直接返回 TokenOAuth 2.0 官方定义了四种授权模式授权码模式、隐式模式、密码模式和客户端凭证模式。其中授权码模式是应用最广、安全性最高的方案也是我强烈推荐你在 Web 应用中优先选择的方案。原因在于它绕开了“Token 经过前端”这个最大的安全风险点。这套模式的名字叫“授权码”核心逻辑是分两步走第一步授权服务器先返回一个短期有效的授权码Authorization Code而且这个码是通过后端服务端重定向的方式交给客户端的第二步客户端拿这个授权码再配合客户端自己的密钥在后端向授权服务器换取 Token。为什么这么绕因为授权码是短期的、一次性的而且单独泄露授权码本身问题不大——因为它必须搭配客户端密钥Client Secret才能换到 Token而客户端密钥是保存在后端服务器上的前端拿不到。Token 也一样通过后端的服务端到服务端通信获取不经过浏览器这样就大大降低了 Token 被脚本注入窃取的风险。你可以理解成授权码是一张“验票凭证”它本身不是门票你得在检票口后端拿着它和身份证一起验才能换到真正的门票Token。我在实际项目里见过不少团队为了图省事直接把用户重定向到授权页面然后把 Token 放在 URL 参数里返回。这种做法的隐患很大——URL 会被浏览器历史记录、代理服务器日志、Referer 头等地方暴露Token 一旦被第三方拿到你的资源就相当于裸奔了。授权码模式虽然多了一次跳转和一次请求但安全收益是实打实的。1.3 参数设计里的核心考量状态码与作用域除了分步换 Token 这件事授权码模式里还有两个容易被忽略但极其关键的参数state状态参数和scope作用域参数。state 参数的用途是防 CSRF跨站请求伪造。它的工作方式是这样的在发起授权请求时客户端先生成一个随机字符串存在自己的会话里然后把这个字符串作为 state 参数拼在授权 URL 上授权服务器回调时会把 state 原样带回来客户端在回调接口里比对这个值是否和会话里的一致如果不一致直接拒绝这次回调。这样就能防止攻击者构造一个授权回调 URL 诱导用户访问从而劫持用户的授权结果。scope 参数则用来控制授权范围。比如一个应用只需要读取用户的公开信息那 scope 就只申请read:user不需要申请read:repo甚至write:repo。这是一个“最小权限”原则的落地——你在授权页面申请多少权限用户就能看到多少权限申请太多反而会让用户产生警惕心理降低转化率。实际对接 GitHub、Google 这类平台的开发者可能都有印象它们的授权页面上会明确列出“这个应用将获得以下权限”这就是通过 scope 控制的。2. 核心角色与授权流程详解2.1 四个角色的职责划分谁在做什么OAuth 2.0 的整个流程里一共涉及四个角色我把它们对应到现实场景里来理解资源所有者Resource Owner就是用户本人拥有资源服务器上的数据。他能决定是否允许第三方应用访问他的数据。客户端Client就是你想接入的那个第三方应用比如一个待办事项 App 想读取你的日历。这里的“客户端”不一定是前端 App它可以是任何需要访问资源的软件。授权服务器Authorization Server负责验证资源所有者的身份并颁发授权码和 Token。它通常和资源服务器是同一套体系里的不同逻辑模块比如 GitHub、微信开放平台的统一授权中心。资源服务器Resource Server存储用户数据的服务比如 GitHub 的/user接口。它负责校验 Token 的有效性和权限范围然后返回相应的数据。需要特别提醒的是授权服务器和资源服务器可以是同一个应用也可以是分开部署的两个服务。很多企业在内部做微服务改造时会把授权服务器单独拆出来做一个统一认证中心各个业务系统作为资源服务器接入。这样做的好处是账号体系和业务数据解耦权限控制可以统一管理缺点是引入了一个高可用要求极高的单点——认证中心挂了所有依赖它的业务都登录不了。2.2 四种授权模式对比各自适用的场景OAuth 2.0 的四种模式不是并列关系而是针对不同的客户端类型设计出来的。我在做技术选型的时候第一件事就是确认客户端是什么类型这决定了用哪种模式。授权模式适用客户端类型核心特点安全级别授权码模式后端参与的 Web 应用、移动应用分两步换 Token客户端密钥由后端保管最高隐式模式纯前端 SPA、无后端参与直接在回调 URL 里返回 Token不经过授权码较低官方已建议弃用密码模式自家前后端、高信任度场景用户直接把用户名密码交给客户端客户端换 Token仅限信任场景不适合第三方客户端凭证模式服务间通信、机器对机器没有用户参与客户端以自己的身份换 Token适用于后台服务这里面我想多说一下隐式模式。在 OAuth 2.0 刚发布的年代纯前端单页应用很流行隐式模式看起来是个好方案不需要后端前端重定向拿 Token 就能用。但它有两个硬伤Token 暴露在 URL 中容易被日志和 Referer 泄露前端没有安全存储 Token 的手段localStorage 和 Cookie 都有各自的漏洞面。因此 OAuth 2.1 草案里已经明确要把隐式模式移除取而代之的是授权码模式 PKCEProof Key for Code Exchange代码交换证明密钥的组合方案。PKCE 的本质是即使客户端是公开的无法安全保存密钥也能通过一个动态生成的 code_verifier 来证明发起授权请求的就是换取 Token 的那个应用。如果你现在在写纯前端应用建议直接上这个方案而不是沿用隐式模式。2.3 什么时候用刷新令牌什么时候用访问令牌关于 Token初学者最常见的困惑是搞不清**访问令牌Access Token和刷新令牌Refresh Token**的区别。简单来说访问令牌是用来访问资源的它有效期短一般是 1 到 24 小时刷新令牌是用来换新的访问令牌的它的有效期更长几天到几个月而且必须存放在安全的后端环境中。为什么不直接让访问令牌的有效期也变长呢因为访问令牌是“亮出来用”的它一旦发了出去你就很难控制它在哪里被记录、被缓存。如果有效期过长泄露后的风险窗口就很大。刷新令牌虽然也有泄露风险但它只在后端和授权服务器之间流通攻击者获取它的难度大得多。而且刷新令牌可以被撤销——比如用户在账号安全设置里“注销所有已登录设备”后端把自己的刷新令牌记录删掉就行但这种做的前提是刷订令牌在你的系统里是可追踪、可撤销的。我在项目里经常看到一种错误设计把刷新令牌也当成普通的 Token 存在浏览器 localStorage 里然后每次刷新 Token 都从前端发起请求。这等于把两把钥匙都挂在门外毫无安全性可言。正确做法是访问令牌可以短期保存在内存里刷新令牌一定要存储在后端前端完全不应该接触它。3. 实操过程与核心环节实现授权码模式全流程本节是全文的重点。我会以“一个待办事项 App 调用 GitHub 获取用户信息”为例子完整拆解一次授权码模式的流程。3.1 前置准备在 GitHub 上注册应用并获取客户端凭证动手之前先在 GitHub 的开发者设置里注册一个 OAuth App。这里有个初学者容易忽略的点回调地址redirect_uri必须和你代码里实际使用的地址完全一致包括协议、域名、端口和路径差一个斜杠都不行。我见过最经典的坑是把回调地址填成http://localhost:8080/callback但本地开发时实际监听的是http://127.0.0.1:8080/callback结果 GitHub 一直报redirect_uri mismatch。注册完成后你会拿到两组关键凭证Client ID公开的可以放在前端代码里用于标识你的应用。Client Secret私密的必须保存在后端泄露了等于你的应用可以被任何人冒充。把这组凭证记录好后面代码里要用到。为了演示方便我这里用 Node.js 和 Express 写一个最小实现但思路可以平移到你用的任何语言和框架。3.2 第一步构建授权链接引导用户授权当用户点击“使用 GitHub 登录”时后端需要生成一个授权链接然后让浏览器重定向过去。这个链接指向授权服务器的/authorize端点关键参数如下https://github.com/login/oauth/authorize ?client_id你的ClientID redirect_urihttp://localhost:8080/callback scoperead:user state随机生成的字符串代码实现大致是这个样子// server.js const express require(express); const crypto require(crypto); const app express(); // 用内存存储 state生产环境建议存在 Redis/Session 中设置过期时间 const stateStore new Map(); app.get(/login, (req, res) { const state crypto.randomBytes(16).toString(hex); stateStore.set(state, { createdAt: Date.now() }); const authorizeUrl https://github.com/login/oauth/authorize ?client_id process.env.CLIENT_ID redirect_uri encodeURIComponent(http://localhost:8080/callback) scoperead:user state state; res.redirect(authorizeUrl); });注意这里的scope参数。GitHub 的read:user表示只读取公开的用户资料这是最小的权限申请。如果你后续要读取用户的仓库列表再考虑扩展 scope不要一开始就申请所有权限。3.3 第二步接收回调校验 state 并换取 Token用户点击“授权”之后GitHub 会将浏览器重定向回你的回调地址并在 URL 上附带两个重要参数code和state。此时你的后端需要在回调接口里做三件事校验state是否与会话中存储的一致防止 CSRF。取出code用它去授权服务器的/access_token端点换 Token。将 Token 存储到后端会话或数据库中然后给前端一个登录成功的信号。以下是完整的回调处理代码app.get(/callback, async (req, res) { const { code, state } req.query; // 1. 校验 state防止 CSRF if (!stateStore.has(state)) { return res.status(400).send(state 不匹配请求可能被篡改); } stateStore.delete(state); // 一次性使用用完即删 if (!code) { return res.status(400).send(缺少授权码); } // 2. 用 code 换 Token这一步必须在后端完成 const tokenResponse await fetch(https://github.com/login/oauth/access_token, { method: POST, headers: { Accept: application/json, Content-Type: application/json, }, body: JSON.stringify({ client_id: process.env.CLIENT_ID, client_secret: process.env.CLIENT_SECRET, code: code, redirect_uri: http://localhost:8080/callback, }), }); const tokenData await tokenResponse.json(); if (tokenData.error) { console.error(换取 Token 失败:, tokenData.error_description || tokenData.error); return res.status(500).send(授权失败); } // 3. 保存访问令牌建议存到 Redis / 数据库中并关联到当前用户 // 这里为了演示简单设置一个 Cookie const sessionId crypto.randomBytes(16).toString(hex); sessions[sessionId] { access_token: tokenData.access_token, refresh_token: tokenData.refresh_token || null, expires_at: Date.now() (tokenData.expires_in || 3600) * 1000, }; res.cookie(session_id, sessionId, { httpOnly: true }); // 前端拿到登录成功信号后可以跳转到用户首页 res.redirect(/dashboard); });这里有几个实操要点code 是一次性的用了一次之后再重复用授权服务器会返回invalid_grant错误。Client Secret 绝对不能在浏览器里出现这个请求只能由后端发起否则任何人都可以用截获的 code 冒充你的应用换 Token。state 建议设为一次性且有过期时间上面的实现里每次用完即删同时在查找时检查createdAt是否过期避免 state 值长期有效。3.4 第三步携带 Token 访问资源服务器拿到访问令牌之后你的应用要请求 GitHub 的/user接口来获取用户信息。这一步很简单在请求头里加一个Authorization字段即可app.get(/dashboard, async (req, res) { const session sessions[req.cookies.session_id]; if (!session || Date.now() session.expires_at) { return res.status(401).send(登录状态已过期请重新登录); } const userResponse await fetch(https://api.github.com/user, { headers: { Authorization: Bearer session.access_token, Accept: application/json, }, }); if (userResponse.status 401) { // Token 失效需要走刷新逻辑 return res.status(401).send(Token 已失效请刷新登录状态); } const userData await userResponse.json(); res.json({ login: userData.login, name: userData.name, avatar: userData.avatar_url }); });这条链路里最需要做好的防御是不要在日志里打印 Authorization 头。很多团队排查线上问题时习惯把请求头打印出来这一打Token 就进了日志系统如果日志又被同步到第三方分析平台风险面就大大扩大了。我通常会要求团队在日志链路里加一条脱敏规则所有Authorization头统一打码为Bearer ***。3.5 第四步刷新 Token保持会话长期有效访问令牌的有效期通常不长GitHub 的 token 有效期默认是 8 小时。用户第二天回来你会发现他的 Token 已经过期了。这时如果有刷新令牌就可以静默换一个新的访问令牌用户完全无感知。async function refreshAccessToken(refreshToken) { const response await fetch(https://github.com/login/oauth/access_token, { method: POST, headers: { Accept: application/json, Content-Type: application/json, }, body: JSON.stringify({ client_id: process.env.CLIENT_ID, client_secret: process.env.CLIENT_SECRET, grant_type: refresh_token, refresh_token: refreshToken, }), }); const data await response.json(); if (data.error) { throw new Error(刷新 Token 失败: data.error_description); } return { access_token: data.access_token, refresh_token: data.refresh_token || refreshToken, // 某些服务会轮换刷新令牌 expires_in: data.expires_in, }; }关于刷新令牌这里有三个值得注意的细节刷新令牌是否轮换有些授权服务器会在每次刷新时返回一个新的刷新令牌旧的就作废了有些则保持不变。如果你的授权服务器支持轮换建议启用这样即使刷新令牌被泄露一次也无法长期使用。刷新令牌也分 scope刷新后新拿到的访问令牌权限范围和原始的刷新令牌一致不会凭空扩大。Refresh Token 泄露怎么办因为刷新令牌生命周期长一旦泄露影响很大。好的方案是给刷新令牌绑定设备信息比如浏览器指纹、IP 段如果检测到异常地点使用就要求重新登录。4. Token 的本质与安全存储设计4.1 Access Token 的格式Opaque Token 与 JWT访问令牌的格式没有统一规定但实际使用中可以分成两大类。一类是不透明令牌Opaque Token就是一串随机字符串资源服务器拿到后要去授权服务器查一下才知道有没有效另一类是JWTJSON Web Token令牌本身携带了用户信息、scope、过期时间等元数据资源服务器只需要验证签名就可以判断令牌有效。两种格式各有取舍。JWT 的优势是无状态资源服务器不需要存储 Session 或者每次远程验证 Token对水平扩容非常友好缺点是一旦签发就无法在到期前撤销除非引入额外的黑名单机制而且 payload 里如果塞太多信息会导致 Token 体积膨胀。不透明令牌则相反它可以随时被撤销但因为资源服务器每次都要去授权服务器验证令牌有效性会增加一次网络往返延迟。这里我想展开说一个 JWT 的误用把敏感数据塞进 payload。JWT 的 payload 只是 Base64 编码不是加密的任何人拿到 Token 用 base64 解码就能看到里面的内容。如果你在 payload 里放了手机号、邮箱、身份证号相当于把用户隐私明文发给所有能截获 Token 的人。正确的做法是 payload 只放sub用户标识、scope、iss、exp这类元数据真正要读的敏感信息还是通过接口去拿。4.2 令牌保存在哪里浏览器端和后端的不同策略开发者在对接 OAuth 2.0 时最常争论的问题就是 Token 到底该存哪。我这个项目里踩过不少坑结论是没有绝对安全的存储位置只能根据业务场景选一个风险最小的方案。如果你的应用有后端参与最佳实践是访问令牌保存在后端的内存变量或 Session 中前端需要用的时候由后端代为请求。刷新令牌保存在后端数据库中并关联用户 ID 和会话 ID支持随时撤销。前端只保存一个不透明的会话标识Session ID用 HttpOnly Cookie 传递。纯前端方案没有自建后端的话令牌只能存在浏览器里选项只有 localStorage、sessionStorage、IndexedDB、Cookie 这几个。它们各自的弱点如下存储位置优点风险localStorage简单、跨标签页共享XSS 攻击可直接读取sessionStorage仅当前标签页有效XSS 攻击仍可读取刷新后不丢但关闭标签页会丢IndexedDB容量大、适合离线数据XSS 攻击仍可读取CookieHttpOnlyXSS 无法读取防御 CSRF 成本高需要考虑 SameSite 策略我的建议是纯前端应用也要尽力减少 Token 在浏览器的暴露时间。可以把访问令牌放在内存变量中每次页面刷新后重新走一遍静默授权流程用 iframe 嵌入隐藏的授权页 PKCE 自动换码而不是直接扔进 localStorage。虽然这样用户每次刷新页面都得等一个异步授权过程但换取的是更高的安全性值得。4.3 scope 的最小权限实践不要贪多scope 是 OAuth 2.0 里约束“这个令牌能干多少事”的机制。我在对接第三方平台时见过一些应用的授权页列了一大堆权限——包括读取仓库、删除仓库、修改个人信息——但实际功能只需要一个“读取用户名”。这不仅是体验问题还是风险问题一旦你的应用被攻破攻击者拿到的令牌权限就等价于你申请的权限。正确的做法是每个功能单独申请 scope尽量解耦。比如你的应用既需要读用户信息又需要代表用户发推文那就申请两个独立的 scope发推文的接口只在用户真正触发发推动作时才需要对应的令牌其他时候用只有只读权限的令牌就够了。5. 常见问题与排查技巧实录5.1 redirect_uri 不匹配这是对接 OAuth 2.0 时出现频率最高的错误报错信息通常是redirect_uri mismatch或者The redirect_uri included is not valid。排查步骤确认授权服务器后台配置的域名和代码里实际使用的完全一致。注意协议http vs https、域名example.com vs www.example.com、端口默认 80 还是 8080、路径/callback vs /callback/。确认有 URL 编码特别是回调地址里带了参数时要整体做一次 encodeURIComponent。确认授权链接里的 redirect_uri 拼写是否正确有没有多空格或者漏字符。5.2 授权码失效或已使用invalid_grant授权码的有效期通常非常短有的只有 1 到 5 分钟而且是一次性的。如果你在本地调试时反复重放同一个授权请求往往第二次就会遇到invalid_grant。排查步骤确认没有在前端代码里尝试用自己的 Client Secret 换 Token因为code是用一次就作废的。确认换了 Token 后没有再次拿同一个 code 去换有些框架会自 动重试需要注意幂等性。确认系统时间没有偏差过大尤其是授权服务器对你的请求做了时间戳校验的场景。5.3 Token 过期怎么处理 401如果你在访问资源服务器时收到 401 Unauthorized先不要急于重新走一遍完整授权流程检查一下刷新令牌还在不在能不能正常刷新。我在项目里遇到过一种情况访问令牌过期后客户端没有捕抓 401而是直接跳转到了登录页用户一刷新又回到首页然后又请求又 401形成一个死循环。后来我们统一封装了一个 HTTP 客户端在响应拦截器里处理 401第一次收到 401 时尝试静默刷新访问令牌刷新成功就自动重放原来的请求刷新失败才引导用户重新登录。这样用户基本感知不到令牌过期的过程。5.4 state 参数校验失败有时候回调接口收到 state 但校验不过多数情况是了 session 或 redis 中保存的 state 与回调的不一致。常见原因包括用户同时打开了多个页面前一个页面的 state 被后一个覆盖了。授权跳转和回调落在不同的集群节点上而 state 存在单机内存里没有共享。浏览器隐私模式下 Cookie 不持久导致 state 丢失。解决方向是把 state 存储在可跨节点共享的存储中比如 Redis设置 5 分钟过期时间并在生成 state 时绑定当前用户会话 ID。5.5 常见问题速查表现象大概率原因排查优先级redirect_uri mismatch回调地址配置不一致1. 核对后台配置2. 核对 URL 编码invalid_grantcode 已失效或重复使用1. 检查是否重复请求2. 检查授权码有效期401 Unauthorized访问令牌过期或无效1. 尝试刷新令牌2. 检查 scope 是否匹配scope 不符合预期申请 scope 与使用场景不匹配1. 确认授权时的 scope2. 查看 Token 实际权限用户授权后跳回空白页回调接口报错未处理1. 查看后端日志2. 检查回调地址是否有非法参数6. 安全实践与避坑经验6.1 生产环境必须做的四件事很多 OAuth 2.0 的接入事故根源不在协议本身而是把生产环境的配置按开发环境的习惯来。根据我自己的经验生产环境上线前至少要做这四步加固强制使用 HTTPSToken 在 HTTP 下传输等于明文传输抓包就能看到。不要在 HTTP 环境下提供任何授权接口。启用 PKCE即使你的应用有后端PKCE 也能提供额外一层保护防止授权码被其他应用截获后使用。对 Token 做加密存储访问令牌和刷新令牌在数据库里不能明文存放建议用 AES-256 或 KMS 加密刷新令牌还要加哈希索引以便快速查询和撤销。设置合理的 Token 过期时间不要图省事把访问令牌的有效期设成 7 天。访问令牌一般是几十分钟到几小时刷新令牌一般不超过 30 天具体看业务场景。6.2 用户退出登录时要清理哪些东西“退出登录”在 OAuth 2.0 体系里不是清除本地 Cookie 就完事的需要做三件事删除本地会话Cookie/Session。吊销授权服务器上的刷新令牌和访问令牌如果授权服务器提供 revoke 接口。撤销应用与用户之间的授权记录确保后续无法通过旧的刷新令牌换到新 Token。很多授权服务器提供了POST /revoke接口调用时需要带上客户端凭证和要撤销的 Token。我在项目里见过一个坑只删了本地会话忘了调 revoke结果用户的刷新令牌在授权服务器上还有效攻击者只要拿到这个令牌就能一直换新 Token用户即使点了退出登录账号还是被人控制着。所以退出登录的接口一定要把“撤销远端令牌”这一步补上。6.3 日志与监控别把 Token 写进日志里前面已经提到过日志脱敏的重要性这里我再展开一点。实际排查问题时最容易泄密的日志场景有捕获第三方接口回调的参数后把整个 query string 打出来里面可能带着 code。在调试阶段打印了请求头包含 Authorization。把整个响应体打出来而响应体里可能包含了 access_token。建议在项目里引入日志脱敏工具对client_secret、access_token、refresh_token、code等敏感字段统一打码同时在监控面板上设置告警检测到日志中出现疑似 Token 的字符串就自动告警。7. 结尾一点个人体会做了这么多年技术我最大的感受是OAuth 2.0 这套协议看着抽象但只要你动手接一次第三方登录再钻进去看一遍交互流程很多概念自然就通了。它本质上就是在回答一个问题——如何在不交出密码的前提下安全地把资源访问权限委托给第三方。搞清楚了这个问题后面再看 OIDCOpenID Connect、PKCE、Token 轮换这些进阶话题都是一通百通。最后再说一个小技巧本地调试 OAuth 2.0 时建议直接在本地起两个项目——一个是授权服务器可以自己写个 Spring Boot 或者 Node 版的最小实现一个是客户端应用。用真实交互代替单纯读文档很多容易混淆的细节比如 code 是一次性的、state 要防重放、scope 最小化都会在你亲手踩过坑之后记得非常牢。这也是我个人最推荐的入门方式。
返回列表