免费注册,打造高效身份管理
博客/开发者/开发者谈 | OAuth 2.0 和 OIDC 协议的关系?(内含必看案例)
开发者谈 | OAuth 2.0 和 OIDC 协议的关系?(内含必看案例)
Authing 官方2022.08.16阅读 2018

撰稿人:Authing 开发者 寻寻觅觅的 Gopher

还记得那个吃披萨的例子吗?

5000 字干货 | IDaaS 身份即服务背后的基石》一文中阐述了 SaaS,PaaS,IaaS 三者的区别。

IDaaS 实际上就是一个基于 SaaS 模式的 IAM 解决方案,也就是云上的身份和访问管理服务,完全由受信任的第三方云服务厂商托管和管理。它允许企业使用单点登录、身份验证和访问控制来提供对任意接入的已实现标准协议应用的安全访问。

而 IDaaS 背后,有两个支撑着其认证授权能力的基石:

OAuth2.0OIDC 协议。

01

OAuth 2.0

OAuth 即 Open Authorization ,开放授权。

OAuth 2.0 是一个授权标准协议,可以使第三方应用获得对资源服务的有限访问。

根据 OAuth 2.0 协议规范,定义了四个角色:

资源所有者(Resource Owner):能够授予对受保护资源访问权限的实体。例如应用的用户是资源的所有者,可以授权其他人访问他的资源。当资源所有者是一个人时,它被称为最终用户。

资源服务器(Resource Server):存储受保护资源的服务器,能够接受并使用访问令牌来响应受保护的资源请求。就是资源服务器接受 Access Token,然后验证它拥有的权限,最后返回对应的资源。这个资源服务器一般是应用本身。

授权服务器(Authorisation Server):服务器向客户端(即应用)颁发访问令牌来验证资源所有者并获得授权。即负责颁发 Access Token 的服务器,例如 IDaaS 就是一个授权服务器。

客户端(Client):需要获取访问令牌以访问资源服务器的应用。经过授权后,授权服务器为客户端颁发 Access Token。后续客户端可以携带这个 Access Token 到资源服务器那访问用户的资源。

在 OAuth 2.0 中一个应用可能既是 Resource Server,也是 Client,具体是什么角色,取决于应用工作的场景。

概念可能有点难嚼,还请慢咽。

这四个角色一直在围绕着一个叫 Access Token 的东西在转圈圈。

Access Token 也就是访问令牌,它用于允许应用访问一个资源 API。用户认证授权成功后,授权服务器会签发 Access Token 给应用。应用后续需要携带 Access Token 访问资源 API,资源服务 API 会检验 Access Token 是否有权限访问,从而决定是否返回对应资源。

而 Access Token 本质上只是一串随机字符串,并不能从中获取到任何信息,检验 Access Token 的步骤还需要资源服务器将它转发到授权服务器上进行解析验证。

了解完 Access Token 之后,我们来关注一下客户端调用方是如何获取到它的,也就是授权模式的选择。

授权码模式(Authorization Code):适用于具有完整前后端的传统 Web 应用以及移动或桌面端应用。

隐式模式(Implicit):适用于没有后端的基于浏览器(JavaScript)的纯前端应用。

密码模式(Resource Owner Password Credentials):适用于资源服务器和客户端之间高度信任的情况下,例如自家应用使用自家的资源。

客户端凭证模式(Client Credentials):适用于没有前端参与,纯后端交互的情况,期间没有用户的参与,客户端自己就是资源所有者。 ......

我们重点关注授权码模式和客户端凭证模式,这两个是最常用的。

先看授权码模式,也叫 code 换 token 模式,我们以 Stack Overflow 使用 GitHub 登录为例(在这个过程中 Stack Overflow 是客户端,GitHub 是资源服务器,提供邮箱头像等资源信息,同时 GitHub 也是授权服务器,会颁发 token 给客户端)。

第一步,点击登录后需要跳转到授权服务器地址,即 GitHub 的地址,并且必须在 URL 上携带 client_id 和 redirect_uri 以及 scope 等信息。

Apache
https://github.com/login/oauth/authorize?  
client_id=01b478c0264a1fbd7183&  
redirect_uri=https://stackauth.com/auth/oauth2/github&  
response_type=code&  scope=user:email&  
state=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 
  • client_id 可以让 GitHub 知道是哪个客户端在请求资源,这里的 01b478c0264a1fbd7183 就是 Stack Overflow 在 GitHub 中注册的客户端 ID;

  • redirect_uri 是授权成功或失败后的回调地址;

  • response_type=code 表示使用授权码模式授权;

  • scope 表示应用正在请求哪些权限;

  • state 是一个随机字符串用来防止 CSRF 攻击。

 

继续第二步,当我们点击授权按钮后,这时授权服务器即 GitHub 会将浏览器重定向到第一步的 redirect_uri 参数指定的网址。并且跳转时,会携带一个授权码 code 参数(由 GitHub 后台生成的)以及 state 参数。

 

Apache
https://stackauth.com/auth/oauth2/github?  
code=1efc47a278d10a04f88e&  
state=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

 

第三步,由于浏览器触发请求了 redirect_uri ,所以 Stack Overflow 网站后台可以接收到请求并拿到授权码 code 和 state ,这时就可以将 state 和第一步生成的 state 对比以防止 CSRF 和其他相关攻击。

第四步,Stack Overflow 可以拿着 client_idclient_secretcode 跟 GitHub 交换令牌,GitHub 收到请求以后就会校验 code 并颁发访问令牌(code 是有过期时间的,并且是一次性的)。

Ruby
// Request
POST 
  code=1efc47a278d10a04f88e&
  client_id=01b478c0264a1fbd7183&
  client_secret=xxxxxx

// Response
Accept: application/json
{
  "access_token":"gho_16C7e42F292c6912E7710c838347Ae178B4a",
  "scope":"user:email",
  "token_type":"bearer"
}

 

最后第五步,Stack Overflow 使用 GitHub 颁发的访问令牌跟 GitHub 获取到所需的资源(用户邮箱地址),然后就走自己的业务流程了,一般就是重定向回首页。

另一个客户端凭证模式就相对简单了,毕竟只是纯后端交互。

例如,一个 B 应用拥有很多 photo 资源,即 B 为资源服务器(假设同时也是授权服务器),A 客户端想要获取 B 的 photo 资源。

第一步,A 应用直接使用 client_idclient_secret 向 B 申请资源。

Groovy
https://b.com/oauth/token?  
grant_type=client_credentials&  
scope=photo&  
client_id=xxx&  
client_secret=xxx

 

response_type=client_credentials 表示使用客户端凭证模式授权。

第二步,B 作为授权服务器验证 A 客户端的 client_idclient_secret 是否合法,然后颁发访问令牌。

第三步,A 客户端携带访问令牌向 B 资源服务器获取 photo 资源。

这期间并没有用户的参与,A 客户端自己就相当于一个“用户”。

 

02

OpenID Connect

讲完 OAuth 2.0 授权,来到 OIDC 认证协议。

如标题,OIDC 全称是 OpenID Connect,是一个基于 OAuth 2.0 的认证 + 授权(OAuth 2.0 提供的能力)协议。

OIDC 可以理解为 OAuth 2.0 的超集,在 OAuth 2.0 之上实现了更多的标准,例如定义了一系列的 EndPoint 。还有一些规范诸如 Session Management,Front-Channel Logout,Back-Channel Logout 等。

OIDC 之所以有认证的功能,是因为在 OAuth 2.0 颁发 Access Token 的基础上,多颁发了一个 ID Token(用户的身份凭证),和 Access Token 是一个随机字符串不同的是,ID Token 是一个 JWT Token 。

ID Token 自身包含了一些用户的基本信息,而且由于 JWT 的防篡改性,让客户端不需要再向授权服务器进行身份验证,就能直接用 ID Token 来进行身份验证。即使 ID Token 包含的用户信息不够,也可以调用 OIDC 定义的 UserInfo EndPoint(用户信息接口)来获取更多的用户信息。

OIDC 协议定义的名词和 OAuth 2.0 协议定义的稍微有些出入:

  • OpenID Provider ,简称 OP :相当于 OAuth 2.0 中的授权服务器,除了负责颁发 Access Token ,还会颁发 ID Token 。例如 IDaaS 就是一个 OP 。

  • Relying Party ,简称 RP :代指 OAuth 2.0 中的客户端。

  • End User ,简称 EU :即用户。

最后, OIDC 的授权流程与 OAuth 2.0 是一样的,主要区别在于 OIDC 授权流程中会额外返回 ID Token。

03

云原生下的 OIDC Provider 服务

IDaaS 的认证和授权使用了 OIDC/OAuth 2.0。说白了,要搭建 IDaaS 得先搭建一个授权服务器 OpenID Provider (更多时候称之为 OIDC Provider )。

但即便完全了解 OIDC 协议,自行实现一套完整的 OIDC Provider 依旧十分繁琐,好在云原生环境下孕育出了很多优秀的项目。本文会简单介绍一下 Go 语言生态下的 dexidp/dex 和 ory/hydra ,感兴趣的可以自行到其官网详细了解。

dexidp/dex

Dex 作为 CNCF 的一个 sandbox 项目,是一个具有可插拔连接器的 OIDC 和 OAuth 2.0 提供商。

它通过”连接器“的身份来充当其他身份提供商的门户,可以将身份验证推送到 LDAP 服务器、SAML 提供商或 GitHub、Google 和 Active Directory 等其他一些成熟的身份提供商中进行验证。客户端只需写一次认证逻辑就可以与 Dex 对接,然后 Dex 来处理特定后端的协议。

ory/hydra

ORY Hydra 是一个 OAuth 2.0 和 OpenID Connect 提供者。

特别一说的是 Hydra 所实现的 OAuth 2.0 协议并不依赖 Go 标准库提供的,而是自实现的 fosite。

另外 ORY Hydra 还提供了一个 5 分钟的快速搭建教程。

 

关于 Authing

Authing 是国内首款以开发者为中心的全场景身份云产品,集成了 OIDC 等所有主流身份认证协议,为企业和开发者提供完善安全的用户认证和访问管理服务。作为云原生架构下的身份云产品,Authing 在产品创建初期,目标就是服务亿级的企业和个人开发者客户,轻量级、易部署、低消耗、技术栈成熟,运维易的云原生技术产品架构,成为了 Authing 的首选。

点击此处了解更多行业身份管理

「解决方案」以及「最佳实践案例」

文章作者

avatar

Authing 官方

0

文章总数

authing blog rqcode
关注 Authing 公众号
随时随地发现更多内容
authing blog rqcode
添加 Authing 小助手
加入 Authing 开发者大家庭