每个人的授权和身份验证简介 OAuth 2.0 登录问题 OpenID Connect 使用 ID 令牌进行身份验证使用访问令牌访问 API 资源和下一步是什么?

2025-05-25

每个人的授权和身份验证

介绍

OAuth 2.0

登录问题

OpenID 连接

使用 ID 令牌进行身份验证

使用访问令牌访问 API

资源和下一步是什么?

我们构建的许多应用程序都需要身份验证和授权。也许你已经开发过应用程序并在其中实现了身份验证和授权——可能是通过导入第三方身份验证库或使用身份平台来实现的。

也许你完成了任务,但你并不清楚幕后发生了什么,或者为什么事情会以某种方式进行。如果你想对使用 OAuth 2.0 和 OpenID Connect 标准时幕后发生的事情有一个基本的了解,请继续阅读!


身份验证很难。为什么?因为身份验证标准定义明确,但要正确执行却颇具挑战性。没关系!我们将以一种通俗易懂的方式讲解身份验证。我们将逐步讲解身份的概念,并在讲解过程中积累知识。讲完之后,你应该已经打下了基础,并且知道哪些方面可能需要深入学习。

这篇文章建议从头到尾阅读。我们会在每个概念的基础上,逐步讲解知识,以便适时引入新的主题。如果您在阅读过程中需要跳转,请记住这一点。


介绍

当我告诉家人或朋友我“从事身份工作”时,他们常常认为这意味着我受雇于政府颁发驾驶执照,或者我帮助人们解决信用卡欺诈问题。

然而,事实并非如此。我之前在 Auth0 工作,这是一家管理数字身份的公司。(我现在是Auth0 大使计划的成员,也是SPPI(安全、隐私、支付和身份)领域的Google 开发者专家。)

数字身份

数字身份是指在特定应用程序提供的功能环境中定义单个用户的一组属性。

这意味着什么?

假设你经营一家在线鞋类零售公司。你的应用用户的数字身份可能是他们的信用卡号、送货地址和购买历史记录。他们的数字身份与你的应用息息相关。

这引导我们...

验证

从广义上讲,身份验证是指验证用户是否是其所说的身份的过程。

一旦系统能够建立这一点,我们就会……

授权

授权涉及授予或拒绝访问资源的权利。

标准

你可能还记得我提到过,授权遵循着明确定义的标准。但这些标准究竟从何而来?

互联网上有许多不同的标准和组织来管理事物的运作方式。在身份验证和授权方面,我们特别关注的两个组织是互联网工程任务组 (IETF) 和 OpenID 基金会 (OIDF)。

IETF(互联网工程任务组)

IETF是一个大型、开放的国际社区,由网络设计师、运营商、供应商和研究人员组成他们关注互联网架构的演变和互联网的平稳运行。

实际上,这是一种很奇特的说法,即专门的专业人士合作编写技术文档来指导我们如何在互联网上做事。

OIDF(OpenID基金会)

OIDF是一个非营利性的国际组织由致力于支持、推广和保护 OpenID 技术的个人和公司组成。

现在我们已经了解了规范以及编写者,让我们回到授权问题并讨论:

OAuth 2.0

OAuth 2.0是 Web 领域最常被提及的规范之一,但同时也经常被误解。这是为什么呢?

OAuth 并非身份验证规范。OAuth处理的是委托授权。请记住,身份验证是验证用户身份。授权则用于授予或拒绝对资源的访问权限。OAuth 2.0 代表用户授予对应用程序的访问权限。(别担心,我们稍后会讲到身份验证部分!)

OAuth 之前

要理解 OAuth 的用途,我们需要回顾一下过去。OAuth 1.0 于 2007 年 12 月制定。在此之前,如果我们需要访问第三方资源,它看起来是这样的:

OAuth 之前

假设您使用了一款名为 HireMe123 的应用。HireMe123 想要为您(用户)设置一个日历事件(例如面试预约)。HireMe123 没有自己的日历;它想使用另一款名为 MyCalApp 的服务来添加事件。

登录 HireMe123 后,HireMe123 会要求您提供 MyCalApp 登录凭证。您需要在 HireMe123 的网站上输入 MyCalApp 用户名和密码。

然后,HireMe123 使用您的 MyCalApp 登录信息来访问 MyCalApp 的 API,然后可以使用您的MyCalApp 凭据创建日历事件。

共享凭证是不好的!

这种方法依赖于将一个应用程序的用户个人凭证与另一个完全不同的应用程序共享,这并不。为什么呢?

首先,HireMe123在保护您的 MyCalApp 登录信息方面承担的风险要小得多。如果 HireMe123 没有妥善保护您的 MyCalApp 凭证,导致其被盗或泄露,有人可能会撰写一些恶意的博客文章,但HireMe123不会像 MyCalApp 那样面临灾难。

HireMe123 对 MyCalApp 的访问权限也非常高。HireMe123 的访问权限和你一样多,因为他们使用了你的凭证来获取访问权限。这意味着 HireMe123 可以读取你所有的日历事件、删除事件、修改你的日历设置等等。

输入 OAuth

这引导我们走向 OAuth。

OAuth 2.0是一个用于执行委托授权的开放标准。它规范了如何在不暴露凭证的情况下授予第三方 API 访问权限。

使用 OAuth,用户现在可以委托HireMe123 代表自己调用 MyCalApp。MyCalApp 可以在第三方客户端调用时限制对其 API 的访问,而不会存在共享登录信息或提供过多访问权限的风险。它使用以下方式实现此目的:

授权服务器

授权服务器是一组用于与用户交互并发放令牌的端点。这有什么用呢?

让我们重新审视一下 HireMe123 和 MyCalApp 的情况,只不过现在我们有了 OAuth 2.0:

使用 OAuth 2.0 授权

MyCalApp 现在有了一个授权服务器。假设 HireMe123 已经在 MyCalApp 注册为已知客户端,这意味着 MyCalApp 的授权服务器将 HireMe123 识别为可以请求访问其 API 的实体。

假设您已经通过 HireMe123 自行设置的身份验证登录。HireMe123 现在想要代表您创建活动。

HireMe123 向 MyCalApp 的授权服务器发送授权请求。作为响应,MyCalApp 的授权服务器会提示您(用户)使用 MyCalApp 登录(如果您尚未登录)。您需要使用 MyCalApp 进行身份验证。

然后,MyCalApp 授权服务器会提示您同意HireMe123 代表您访问 MyCalApp 的 API。浏览器中会打开一个提示框,专门询问您是否同意 HireMe123 添加日历事件(但仅此而已)。

如果您同意,MyCalApp 授权服务器将向 HireMe123 发送授权码。这会让 HireMe123 知道 MyCalApp 用户(您)确实同意允许 HireMe123 使用其(您的)MyCalApp 添加活动。

然后,MyCalApp 将向 HireMe123 发放访问令牌。HireMe123 可以使用该访问令牌在您已接受的权限范围内调用 MyCalApp API,并使用 MyCalApp API 为您创建事件。

现在什么危险的事情都没有发生! MyCalApp 要求用户使用 MyCalApp 登录。HireMe123 并没有要求用户提供 MyCalApp 的凭证。凭证共享和过多访问权限的问题已经不再是问题了。

那么身份验证呢?

至此,我希望大家已经明确了OAuth 是用于授权访问的。它并不涵盖身份验证。在我们上面提到的流程中,任何涉及身份验证的环节,登录都由 HireMe123 或 MyCalApp 自行决定实现的登录流程进行管理。OAuth 2.0并没有规定如何实现这一点:它只涵盖授权第三方 API 访问。

那么为什么身份验证和 OAuth 经常被相提并论呢?

登录问题

OAuth 2.0 建立了访问第三方 API 的方式后,应用程序也希望使用其他帐户登录用户。使用我们的例子:假设 HireMe123 希望 MyCalApp 用户能够使用他们的 MyCalApp 帐户登录 HireMe123,尽管他们没有注册 HireMe123 帐户。

但正如我们上面提到的,OAuth 2.0 用于委托访问。它本身并不是一个身份验证协议。但这并没有阻止人们尝试像身份验证协议一样使用它,并且这带来了一些问题。

使用访问令牌进行身份验证的问题

如果 HireMe123 认为使用访问令牌成功调用 MyCalApp 的 API 意味着用户可以被视为通过 HireMe123 进行身份验证,那么我们就会遇到问题,因为我们无法验证访问令牌是否颁发给了特定的个人。

例如:

  • 有人可能从其他用户那里窃取了访问令牌
  • 访问令牌可以从另一个客户端(不是 HireMe123)获取并注入到 HireMe123 中

这被称为混淆代理问题。HireMe123 不知道这个令牌从何而来,也不知道它是为谁颁发的。我们回想一下:身份验证就是验证用户的身份是否与他们声称的身份相符。HireMe123 虽然可以使用这个访问令牌访问 API,但却无法知道这一点。

如上所述,这并没有阻止人们滥用访问令牌和 OAuth 2.0 进行身份验证。很快我们就发现,在 OAuth 2.0 之上对身份验证进行形式化是必要的,这样才能允许第三方应用程序登录,同时确保应用程序及其用户的安全。

OpenID 连接

这引出了名为OpenID Connect (简称 OIDC)的规范。OIDC 是基于 OAuth 2.0 的规范,用于规范如何对用户进行身份验证。OpenID基金会 (OIDF)是 OIDC 标准的管理机构。

OIDC 是一个身份层,用于通过授权服务器对用户进行身份验证。请记住,授权服务器会颁发令牌令牌是用于在各方(例如授权服务器、应用程序或资源 API)之间传输信息的编码数据片段。在 OIDC 和身份验证的情况下,授权服务器会颁发ID 令牌

ID 令牌

ID 令牌提供有关身份验证事件的信息,并用于识别用户。ID 令牌旨在供客户端使用。它们采用固定格式,客户端可以解析和验证令牌,从中提取身份信息,从而对用户进行身份验证。

OIDC 声明了ID 令牌的固定格式,即:

JSON Web 令牌 (JWT)

JSON Web Tokens,或称JWT(有时发音为“jot”),由三个 URL 安全字符串段用句点连接而成.

报头段

第一个段是标头段。它可能看起来像这样:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9

标头段是一个 JSON 对象,包含签名算法和令牌类型。它经过base64Url编码(以文本形式表示的字节数据,对 URL 和文件名安全)。

解码后,它看起来像这样:

{
  "alg": "RS256",
  "typ": "JWT"
}
Enter fullscreen mode Exit fullscreen mode

有效载荷段

第二段是有效载荷段。它可能看起来像这样:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0

这是一个包含数据声明的 JSON 对象,数据声明是关于用户和身份验证事件的语句。例如:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}
Enter fullscreen mode Exit fullscreen mode

这也是base64Url经过编码的。

加密段

最后一段是加密段,或者说签名段。JWT 经过签名,因此在传输过程中无法被修改。授权服务器签发令牌时,会使用密钥对其进行签名。

当客户端收到 ID 令牌时,客户端也会使用密钥验证签名。(如果使用了非对称签名算法,则签名和验证会使用不同的密钥;在这种情况下,只有授权服务器才拥有对令牌进行签名的权限。)

如果这看起来令人困惑,请不要担心。其工作原理的细节应该不会困扰您,也不会妨碍您有效地使用基于令牌的身份验证的授权服务器。如果您有兴趣揭开 JWT 签名背后的术语、专业术语和细节,请查看我的文章《为每个人签名和验证 JSON Web 令牌 (JWT)》

索赔

现在我们已经了解了JWT 的结构,接下来让我们进一步讨论一下声明,即来自有效负载段的那些语句。根据其名称,ID 令牌提供身份信息,这些信息存在于声明中。

身份验证声明

我们将从有关身份验证事件的声明开始。以下是这些声明的几个示例:

{
  "iss": "https://{you}.authz-server.com",
  "aud": "RxHBtq2HL6biPljKRLNByqehlKhN1nCx",
  "exp": 1570019636365,
  "iat": 1570016110289,
  "nonce": "3yAjXLPq8EPP0S",
  ...
}
Enter fullscreen mode Exit fullscreen mode

ID 令牌中所需的一些身份验证声明包括:

  • iss (issuer):JWT 的发布者,例如授权服务器
  • aud (受众):JWT 的预期接收者;对于 ID 令牌,这必须是接收令牌的应用程序的客户端 ID
  • exp (到期时间):到期时间;此时间之后不得接受 ID 令牌
  • iat (签发时间):签发 ID 令牌的时间

Anonce 将客户端的授权请求与其收到的令牌绑定。Nonce 是一个加密随机字符串,由客户端创建并随授权请求发送。授权服务器随后将 Nonce 放入返回给应用的令牌中。应用会验证令牌中的 Nonce 是否与授权请求中发送的 Nonce 匹配。这样,应用就可以验证令牌是否来自它最初请求令牌的地方。

身份声明

声明还包括关于最终用户的陈述。以下是一些此类声明的示例:

{
  "sub": "google-oauth2|102582972157289381734",
  "name": "Kim Maida",
  "picture": "https://gravatar[...]",
  "twitter": "https://twitter.com/KimMaida",
  "email": "kim@gatsbyjs.com",
  ...
}
Enter fullscreen mode Exit fullscreen mode

ID 令牌中的一些标准配置文件声明包括:

  • sub (subject):用户的唯一标识符;必填
  • email
  • email_verified
  • birthdate
  • ETC。

现在我们已经完成了有关重要规范( OAuth 2.0OpenID Connect )的速成课程,现在是时候看看如何将我们的身份知识付诸实践了

使用 ID 令牌进行身份验证

让我们看看实际中的 OIDC 身份验证。

请注意,这是一个简化的图表。根据您的应用程序架构,可能会有几种不同的流程。

使用浏览器中的 ID 令牌进行身份验证

这里的实体包括:浏览器、在浏览器中运行的应用程序以及授权服务器。当用户想要登录时,应用程序会向授权服务器发送授权请求。授权服务器会验证用户的凭据,如果一切正常,授权服务器会向应用程序发出 ID 令牌。

然后,客户端应用程序解码 ID 令牌(即JWT)并进行验证。这包括验证签名,并且还必须验证声明。声明验证的一些示例包括:

  • 发行者(iss):此令牌是否由预期的授权服务器颁发?
  • 受众(aud):我们的应用程序是此令牌的目标接收者吗?
  • 有效期(exp):此令牌是否在有效使用时间范围内?
  • nonce(nonce):我们可以将此令牌与我们的应用程序发出的授权请求联系起来吗?

一旦我们确认了 ID 令牌的真实性,用户就通过了身份验证。我们现在还可以访问身份声明并知道该用户是

现在用户已通过身份验证。是时候与 API 进行交互了。

使用访问令牌访问 API

我们之前讨论过访问令牌,当时我们正在研究委托访问如何与OAuth 2.0 和授权服务器协同工作。让我们回顾一下 HireMe123 和 MyCalApp 的场景,来了解一下它的一些工作原理。

访问令牌

访问令牌用于授予对资源的访问权限。使用 MyCalApp 授权服务器颁发的访问令牌,HireMe123 可以访问 MyCalApp 的 API。

与OIDC声明为JSON Web Tokens 的ID Tokens不同访问令牌没有特定的定义格式。它们不必(也不一定)是 JWT。然而,许多身份解决方案使用 JWT 作为访问令牌,因为这种格式支持验证。

访问令牌对客户端不透明

访问令牌用于资源 API ,因此对客户端而言,访问令牌不透明非常重要。为什么?

访问令牌可能随时更改。它们应该具有较短的有效期,以便用户可以频繁获取新令牌。它们还可以重新颁发以访问不同的 API 或行使不同的权限。客户端应用程序不应包含依赖于访问令牌内容的代码。这样做的代码会很脆弱,几乎肯定会崩溃。

访问资源 API

假设我们想使用访问令牌从单页应用程序调用 API。这是什么样子的?

上面我们已经介绍了身份验证,因此假设用户已在浏览器中登录到我们的 JS 应用。应用向授权服务器发送授权请求,请求访问令牌以调用 API。

使用访问令牌访问 API

然后,当我们的应用程序想要与 API 交互时,我们将访问令牌附加到请求标头,如下所示:

# HTTP request headers
Authorization: 'Bearer eyj[...]'
Enter fullscreen mode Exit fullscreen mode

授权请求随后被发送到 API,API 使用中间件验证令牌。如果一切正常,API 会将数据(例如 JSON)返回给浏览器中运行的应用程序。

这很棒,但你现在可能正在想些什么。之前我们提到过,OAuth 解决了访问权限过多的问题。那么,OAuth 是如何解决这个问题的呢?

作用域委托

API 如何知道应该给予请求使用其 API 的应用程序什么级别的访问权限?我们通过作用域来实现这一点。

范围“限制了应用程序代表用户执行的操作”。它们无法授予用户尚未拥有的权限。例如,如果 MyCalApp 用户无权设置新的 MyCalApp 企业帐户,那么授予HireMe123的范围也将永远不允许用户设置新的企业帐户。

作用域将访问控制委托给 API 或资源。然后,API 负责将传入的作用域与实际用户权限相结合,以做出适当的访问控制决策。

让我们通过一个例子来解释一下。

我正在使用 HireMe123 应用,HireMe123 想要访问第三方 MyCalApp API 来代表我创建活动。HireMe123 已经向 MyCalApp 的授权服务器请求了MyCalApp 的访问令牌。此令牌包含一些重要信息,例如:

  • sub:(我的 MyCalApp 用户 ID)
  • aud:(MyCalAppAPI观众指出此令牌适用于 MyCalApp API)
  • scope:(write:events范围表明 HireMe123 有权使用 API 将事件写入我的日历)

HireMe123 向 MyCalApp API 发送一个请求,并在其授权标头中包含访问令牌。当 MyCalApp API 收到此请求时,它可以看到该令牌包含一个write:events作用域。

但是 MyCalApp 托管着数十万用户的日历账户。除了查看scope令牌中的 之外,MyCalApp 的 API 中间件还需要检查sub主题标识符,以确保来自 HireMe123 的请求只能行使我的权限,使用我的MyCalApp 账户创建活动。

具有范围和 API 访问控制的委托授权

在委托授权的上下文中,范围表示应用程序可以代表用户执行的操作。它们是用户全部功能的一部分。

授予同意

还记得授权服务器询问 HireMe123 用户是否同意允许 HireMe123 使用用户的权限访问 MyCalApp 吗?

该同意对话框可能看起来像这样:

同意对话框流程:HireMe123 正在请求访问您的 MyCalApp 帐户以写入:日历

HireMe123 可以要求各种不同的范围,例如:

  • write:events
  • read:events
  • read:settings
  • write:settings
  • ...ETC。

一般来说,我们应该避免使用特定于用户的权限来重载作用域。作用域用于为应用程序委派权限。但是,如果您的授权服务器提供基于角色的访问控制 (RBAC) ,则可以为单个用户添加不同的作用域

使用RBAC,您可以在授权服务器中设置具有特定权限的用户角色。然后,当授权服务器颁发访问令牌时,它可以将特定用户的角色纳入其范围。


资源和下一步是什么?

我们讲了很多内容,但仍然远远没有涵盖所有内容。我希望这能成为一门关于身份、授权和身份验证的速成课程。

为了进一步揭开 JWT 的神秘面纱,请阅读我的文章《为每个人签署和验证 JSON Web 令牌》

如果您想了解有关这些主题的更多信息,这里有一些很棒的资源可以帮助您进一步了解:

了解更多

Auth0 文档中的“学习身份”视频系列Auth0工程师新员工身份培训的讲座部分,由首席架构师Vittorio Bertocci主讲。如果您想以 Auth0 的方式学习身份,它完全免费,并且对所有人开放(您甚至无需通过推文或电子邮件付费!)。

OAuth 2.0 和 OpenID Connect 规范虽然内容复杂,但一旦你熟悉了相关术语并具备了基础的身份认证知识,它们就会变得非常实用、信息丰富,并且更容易理解。点击此处查看:OAuth 2.0 授权框架OpenID Connect 规范

JWT.io是一个JSON Web Token资源,它为各种技术提供调试工具和 JWT 签名/验证库目录。

OpenID Connect Playground一个调试器,可让开发人员逐步探索和测试OIDC调用和响应。

谢谢你!

如果您想聊天,我的推特账号是@KimMaida,我也会在各种会议和活动上发言——至少在新冠疫情之前是这样。我已经以演示文稿的形式分享了这些内容,希望在旅行和线下活动恢复后能再次分享。希望有机会再见,非常感谢您的阅读

文章来源:https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3
PREV
我现在用什么来代替谷歌
NEXT
职业发展和个人成就的 7 个秘诀