4、OAuth2.0授权框架:四种授权模式详解

OAuth2.0 这东西,说白了就是一个「门禁系统」。

你的应用想访问用户的资源,不能直接拿钥匙去开人家的门。你得先问用户要一张「通行证」,然后拿着通行证去换「临时钥匙」。这个流程,就是 OAuth2.0 的核心思想。

我最早接触 OAuth2.0 是在做第三方登录的时候。当时被各种「授权码」、「令牌」、「刷新」搞得晕头转向。后来踩了几个坑,才真正理解这四种模式到底该怎么用。

4.1 授权码模式(Authorization Code)

这是最常用、也是最安全的一种模式。我个人的习惯是,只要你的应用有后端服务,优先选它。

流程大概是这样的:

  1. 用户点击「登录」,你的应用把用户引导到授权服务器。
  2. 用户同意授权后,授权服务器返回一个「授权码」到你的后端。
  3. 你的后端拿着这个授权码,再去请求「访问令牌」。
  4. 拿到令牌后,就可以访问用户资源了。

关键点:授权码只走后端通道,不经过浏览器。这就避免了令牌被截获的风险。

我在项目中遇到过一个问题:有人把授权码直接暴露在前端 URL 里。嗯,这其实问题不大,因为授权码是一次性的,而且必须配合 client_secret 才能换令牌。但如果你把 client_secret 也写在前端代码里……那就等着被黑吧。

我的建议:授权码模式 + PKCE(Proof Key for Code Exchange)是目前最稳妥的方案。尤其是移动端或单页应用,一定要加上 PKCE。

4.2 隐式模式(Implicit)

这个模式现在基本被淘汰了。说白了,它就是为了简化流程而设计的——直接返回令牌,不经过授权码那一步。

你想想看,令牌直接暴露在浏览器里,多危险。我以前维护过一个老系统,用的就是隐式模式。结果有一次安全审计,直接被列为高危漏洞。

注意:OAuth2.0 安全最佳实践已经明确不建议使用隐式模式。如果你还在用,赶紧迁移到授权码模式 + PKCE。

为什么会被淘汰?因为单页应用(SPA)现在有了更好的选择。你完全可以用授权码模式,配合 PKCE 来保证安全。何必冒险用隐式模式呢?

4.3 密码模式(Resource Owner Password Credentials)

这个模式,说白了就是「你把用户名密码直接给我,我去帮你换令牌」。

听起来是不是很粗暴?没错,它确实简单。但代价就是——你的应用必须完全信任授权服务器。而且用户要把密码交给你,这本身就是一种风险。

适用场景:

  • 你自己的第一方应用(比如公司内部的系统)
  • 迁移场景,老系统改造过渡期
  • 绝对信任的环境

我曾经在一个内部工具里用过密码模式。当时觉得反正都是自己人,无所谓。后来发现,只要有一个员工的账号被钓鱼,整个系统的令牌就全暴露了。嗯,从那以后我再也不敢随便用这个模式了。

避坑指南:密码模式不要用于第三方应用。一旦你的应用被攻破,用户的密码就全丢了。这个责任你担不起。

4.4 客户端凭证模式(Client Credentials)

这个模式最简单——没有用户参与,只有应用自己。

你想想看,什么时候需要这种模式?就是你的微服务 A 要调用微服务 B 的 API,不需要代表任何用户,只需要证明「我是我」就行了。

典型场景:

  • 服务间通信
  • 后台定时任务
  • 数据同步

我在做微服务架构时,经常用这个模式来做服务间的认证。比如订单服务要调用用户服务获取用户信息,直接用客户端凭证换一个令牌,简单高效。

注意:客户端凭证模式没有刷新令牌的概念。令牌过期了,直接重新申请就行。因为 client_id 和 client_secret 都在你手里,随时可以换新的。

4.5 如何选择?一张表说清楚

模式 适用场景 安全等级 我的推荐
授权码模式 有后端的 Web 应用、移动端 ⭐⭐⭐⭐⭐ 首选,配合 PKCE 更安全
隐式模式 已淘汰,不建议使用 ⭐⭐ 赶紧迁移
密码模式 第一方应用、迁移过渡 ⭐⭐⭐ 谨慎使用,别给第三方
客户端凭证 服务间通信、后台任务 ⭐⭐⭐⭐ 服务间通信的首选

我个人习惯是:

  • 有用户参与的,一律用授权码模式 + PKCE。
  • 服务间通信,用客户端凭证模式。
  • 密码模式?除非万不得已,否则别碰。
  • 隐式模式?忘掉它吧。

最后提醒一句:OAuth2.0 只是授权框架,不是认证协议。它解决的是「你能访问什么」,而不是「你是谁」。如果你需要认证,请结合 OpenID Connect 使用。这个我们后面会详细讲。

好了,四种模式讲完了。你想想看,你的项目适合哪一种?别急着选,先搞清楚你的场景里有没有用户参与,有没有后端服务,安全要求有多高。选对了模式,后面的事情就顺了。