oauth2原理及应用

OAuth2 的简单解释

OAuth2 是目前比较流行的授权机制,用来授权第三方应用来使用用户的一些数据

通过OAuth2可以比较简单的实现跨平台的资源共享,下面简单介绍一下OAuth2具体解决了哪方面的问题;

一个关于小区送快递的场景

在一个大型的居民小区,小区入口处的门有密码锁;

1558925689197

进出门的时候,需要业主输入密码下能进入;

1558925719706

但是小区经常会有外卖和快递员出入,快递员需要在有快件派送的时候有权限进入小区,现在必须有一种办法可以让快递员在没有账号密码的情况下通过门禁系统,进入小区

1558925875324

如果业主将密码告诉了快递员, 那快递员就拥有了和业主一样的权限,快递员可以用密码反反复复出入小区, 好像并不能这样设计。

小区授权机制设计

对于以上问题,可以设计一套如下的授权方案,授权的流程如下

  1. 门禁系统的密码输入下方,提供一个获取授权的按钮。快递员需要首先按这个按钮,去申请授权。
  2. 按下按钮以后, 业主的手机就会弹出对话框, 有人正在要求授权。系统还会显示出该快递员的姓名,工号和所属的快递公司,业主确认快递员的请求属实,就会点击按钮,告诉门禁系统,我同意给与他进入小区的权限;
  3. 门禁系统得到业主的确认以后,向快递员显示一个进入小区的令牌(一个临时密码, 一般会有一个期限)。
  4. 快递员输入临时密码后,便可以进入小区;

互联网授权机制OAuth

关于快递的例子,解决了一个不属于本小区用户,通过业主(资源所有者)的授权,有了临时进入小区,执行一些业主权限的问题;

把该例子应用到互联网应用的场景,就是OAuth的作用了;

一、居民小区就相当于拥有用户数据资源的资源服务器。比如,支付宝存储了我们的头像和信用分等信息,想要获取这些数据,用户一定要先成功登陆支付宝;

二、快递员相当于第三方应用,想要穿过门禁系统,进入小区。比如,某贷款机构想要通过支付宝,获取用户的芝麻饮用分来判断贷款金额;

三、就是业主本人相当于互联网应用的资源所有者,同意快递员第三方进入小区,执行业主本人的一些权限。

总结: OAuth就是一种授权机制, 数据所有者告诉系统,同意并授权第三方进入系统,获取一些指定的数据的权限。系统从而会提供一个短期的令牌给第三方,在一定时间内,第三方都可以通过该令牌获取用户已经授权获取的数据;OAuth解决了第三方应用获取平台用户数据的问题;

OAuth2的一些基本概念

什么是OAuth2.0

OAuth 2.0, 允许第三方应用程序来代表资源所有者获得对HTTP服务的有限访问权限以自己的名义获取访问权限。

在传统的客户端 - 服务器身份验证模型中,客户端通过使用资源所有者的凭据向服务器进行身份验证来请求服务器上的访问受限资源(受保护资源)。为了向第三方应用程序提供对受限资源的访问,资源所有者与第三方共享其凭据。这会产生一些问题和限制。

OAuth通过引入授权层并将客户端的角色与资源所有者的角色分开来解决这些问题。在OAuth中,客户端请求访问由资源所有者控制并由资源服务器托管的资源,并发出与资源所有者不同的凭据集。

客户端不是使用资源所有者的凭证来访问受保护资源,而是获取访问令牌 - 表示特定范围,生命周期和其他访问属性的字符串。授权服务器在资源所有者的批准下向第三方客户端颁发访问令牌。客户端使用访问令牌来访问资源服务器托管的受保护资源

什么是OpenID Connect 1.0

OpenID Connect 1.0是OAuth 2.0协议之上的简单身份层。它使客户端能够根据授权服务器执行的身份验证来验证最终用户的身份,以及以可互操作和类似REST的方式获取有关最终用户的基本配置文件信息。

作为背景,OAuth 2.0授权框架和OAuth 2.0承载令牌使用规范为第三方应用程序提供了一个通用框架,以获取和使用对HTTP资源的有限访问。它们定义了获取和使用访问令牌来访问资源的机制,但没有定义标准方法来提供身份信息。值得注意的是,如果没有分析OAuth 2.0,它就无法提供有关最终用户身份验证的信息。

OpenID Connect实现身份验证,作为OAuth 2.0授权过程的扩展。

OpenID Connect允许所有类型的客户端(包括基于Web,移动和JavaScript客户端)请求和接收有关经过身份验证的会话和最终用户的信息。规范套件是可扩展的,允许参与者在对它们有意义时使用可选功能,例如身份数据加密,OpenID提供程序的发现和会话管理。

OAuth2 的角色定义

  1. 资源所有者

    资源所有者是 OAuth 2 四大基本角色之一,在 OAuth 2 标准中,资源所有者即代表授权客户端访问本身资源信息的用户(User),也就是应用场景中的“开发者A”。客户端访问用户帐户的权限仅限于用户授权的“范围”(aka. scope,例如读取或写入权限)。

    如果没有特别说明,下文中出现的”用户”将统一代表资源所有者。

  2. 用户认证中心

    验证用户身份的地方,比如网站的登录系统(密码验证/ session验证);

  3. 资源服务器(resource server)

    资源服务器托管了所有的受保护的用户资源等, 存储服务资源的地方就是资源服务器;

    我们使用授权的目的,就是获取在资源服务器上和用户相关资源的资格;

  4. 授权中心(oauth2 server)

    资源服务器托管了受保护的用户账号信息,而授权服务器验证用户身份然后为客户端派发资源访问令牌。

    在上述应用场景中,Github 既是授权服务器也是资源服务器,个人信息和仓库信息即为资源(Resource)。而在实际工程中,不同的服务器应用往往独立部署,协同保护用户账户信息资源。

  5. 客户端 ( oauth2 client )

    执行授权服务流程的后台程序, 该部分一般要由第三方独立开发; 有的资源提供商,会提供sdk等供用户进行客户端的开发;

  6. 用户终端(浏览器…)

    调用客户端执行授权过程的地方,一般为浏览器。。。

令牌与密码

令牌(token)与密码(password)的作用是一样的,都可以进入系统,但是有三点差异。

(1)令牌是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。

(2)令牌可以被数据所有者撤销,会立即失效。以上例而言,屋主可以随时取消快递员的令牌。密码一般不允许被他人撤销。

(3)令牌有权限范围(scope),比如只能进小区的二号门。对于网络服务来说,只读令牌就比读写令牌更安全。密码一般是完整权限。

上面这些设计,保证了令牌既可以让第三方应用获得权限,同时又随时可控,不会危及系统安全。这就是 OAuth 2.0 的优点。

注意,只要知道了令牌,就能进入系统。系统一般不会再次确认身份,所以令牌必须保密,泄漏令牌与泄漏密码的后果是一样的。这也是为什么令牌的有效期,一般都设置得很短的原因。

OAuth2.0 的授权模式与使用

OAuth 2.0 规定了四种获得令牌的流程。下面就是这四种授权方式。

Auth2.0的四种授权模式

  • ​ 授权码模式(Authorization Code)(支持refresh token)
  • ​ 隐藏模式(Implicit)(不支持refresh token)
  • ​ 密码模式(Resource Owner Password Credentials) (支持refresh token)
  • ​ 客户端模式(Client Credentials) (不支持refresh token)

注意,不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的。

授权码模式

授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。

这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。

第一步,A 网站提供一个链接,用户点击后就会跳转到 B 网站,授权用户数据给 A 网站使用。

第二步,用户跳转后,B 网站会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回redirect_uri参数指定的网址。跳转时,会传回一个授权码。

第三步,A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。

第四步,B 网站收到请求以后,就会颁发令牌。具体做法是向redirect_uri指定的网址,发送一段 JSON 数据包含了令牌的详细内容。

1558937107718

隐藏模式

有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。

第一步,A 网站提供一个链接,要求用户跳转到 B 网站,授权用户数据给 A 网站使用。

第二步,用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回redirect_uri参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站。

1558937182421

这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。

密码模式

如果你高度信任某个应用,也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为”密码式”(password)。

第一步,A 网站要求用户提供 B 网站的用户名和密码。拿到以后,A 就直接向 B 请求令牌。

第二步,B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 因此拿到令牌。

这种方式需要用户给出自己的用户名/密码,显然风险很大,因此只适用于其他授权方式都无法采用的情况,而且必须是用户高度信任的应用。

客户端模式

最后一种方式是凭证式(client credentials),适用于没有前端的命令行应用,即在命令行下请求令牌。

第一步,A 应用在命令行向 B 发出请求。

第二步,B 网站验证通过以后,直接返回令牌。

这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。

令牌的使用

A 网站拿到令牌以后,就可以向 B 网站的 API 请求数据了。

此时,每个发到 API 的请求,都必须带有令牌。具体做法是在请求的头信息,加上一个Authorization字段,令牌就放在这个字段里面。

1
2
curl -H "Authorization: Bearer ACCESS_TOKEN" \
"https://api.b.com"

上面命令中,ACCESS_TOKEN就是拿到的令牌。

更新令牌

令牌的有效期到了,如果让用户重新走一遍上面的流程,再申请一个新的令牌,很可能体验不好,而且也没有必要。OAuth 2.0 允许用户自动更新令牌。

具体方法是,B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(refresh token 字段)。令牌到期前,用户使用 refresh token 发一个请求,去更新令牌。

1
2
3
4
5
https://b.com/oauth/token?
grant_type=refresh_token&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
refresh_token=REFRESH_TOKEN

上面 URL 中,grant_type参数为refresh_token表示要求更新令牌,client_id参数和client_secret参数用于确认身份,refresh_token参数就是用于更新令牌的令牌。

第三方授权例子

一、场景举例

举例来说,A 网站允许使用B网站账号登录,背后就是下面的流程。

  1. A 网站让用户跳转到B网站。
  2. B要求用户登录,然后询问”A 网站要求获得 xx 权限,你是否同意?”
  3. 用户同意,B就会重定向回 A 网站,同时发回一个授权码。
  4. A 网站使用授权码,向 B 请求令牌。
  5. B网站返回令牌.
  6. A 网站使用令牌,向B资源服务器请求用户数据。

二、授权流程

1558938880561

  1. Authrization Request
    客户端向用户请求对资源服务器的authorization grant
  2. Authorization Grant(Get)
    如果用户授权该次请求,客户端将收到一个authorization grant
  3. Authorization Grant(Post)
    客户端向授权服务器发送它自己的客户端身份标识和上一步中的authorization grant,请求访问令牌。
  4. Access Token(Get)
    如果客户端身份被认证,并且authorization grant也被验证通过,授权服务器将为客户端派发access token。授权阶段至此全部结束。
  5. Access Token(Post && Validate)
    客户端向资源服务器发送access token用于验证并请求资源信息。
  6. Protected Resource(Get)
    如果access token验证通过,资源服务器将向客户端返回资源信息。

三、豆瓣授权流程

  1. User Authorization Request

首先,客户端构造了一个用于请求authorization code的URL并引导User-agent跳转访问。

1
2
3
4
5
6
https://authorization-server.com/auth
?response_type=code
&client_id=29352915982374239857
&redirect_uri=https%3A%2F%2Fexample-client.com%2Fcallback
&scope=create+delete
&state=xcoiv98y2kd22vusuye3kch
  • response_type=code
    此参数和参数值用于提示授权服务器当前客户端正在进行Authorization Code授权流程。
  • client_id
    客户端身份标识。
  • redirect_uri
    标识授权服务器接收客户端请求后返回给User-agent的跳转访问地址。
  • scope
    指定客户端请求的访问级别。
  • state
    由客户端生成的随机字符串,步骤2中用户进行授权客户端的请求时也会携带此字符串用于比较,这是为了防止CSRF攻击。
  1. User Authorizes Applcation

当用户点击上文中的示例链接时,用户必须已经在授权服务中进行登录(否则将会跳转到登录界面,不过 OAuth 2 并不关心认证过程),然后授权服务会提示用户授权或拒绝应用程序访问其帐户。以下是授权应用程序的示例:

1559009900193

  1. Authorization Code Grant

如果用户确认授权,授权服务器将重定向User-agent至之前客户端提供的指向客户端的redirect_uri地址,并附带codestate参数(由之前客户端提供),于是客户端便能直接读取到authorization code值。

1
2
3
https://example-client.com/redirect
?code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3
&state=xcoiv98y2kd22vusuye3kch

state值将与客户端在请求中最初设置的值相同。客户端将检查重定向中的状态值是否与最初设置的状态值相匹配。这可以防止CSRF和其他相关攻击。

code是授权服务器生成的authorization code值。code相对较短,通常持续1到10分钟,具体取决于授权服务器设置。

  1. Access Token Request

现在客户端已经拥有了服务器派发的authorization code,接下来便可以使用authorization code和其他参数向服务器请求access token(POST方式)。其他相关参数如下:

  • grant_type=authorization_code - 这告诉服务器当前客户端正在使用Authorization Code授权流程。
  • code - 应用程序包含它在重定向中给出的授权码。
  • redirect_uri - 与请求authorization code时使用的redirect_uri相同。某些资源(API)不需要此参数。
  • client_id - 客户端标识。
  • client_secret - 应用程序的客户端密钥。这确保了获取access token的请求只能从客户端发出,而不能从可能截获authorization code的攻击者发出。
  1. Access Token Grant

服务器将会验证第4步中的请求参数,当验证通过后(校验authorization code是否过期,client idclient secret是否匹配等),服务器将向客户端返回access token

1
2
3
4
5
6
7
{
"access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
"token_type":"bearer",
"expires_in":3600,
"refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
"scope":"create delete"
}

至此,授权流程全部结束。直到access token 过期或失效之前,客户端可以通过资源服务器API访问用户的帐户,并具备scope中给定的操作权限。

Ory Hydra OAuth2.0 框架

ORY Hydra解决了身份验证和授权问题,是OAuth 2.0和OpenID Connect提供商。

什么是ORY Hydra

ORY Hydra是OAuth 2.0和OpenID Connect Provider。因此,它能够发出访问,刷新和ID令牌。与其他项目相反,ORY Hydra不提供用户管理(登录,注销,配置文件管理,注册),而是使用基于重定向的流和REST API将用户身份验证(登录)委派给您实现的服务,控制。这允许您构建适合您的用户管理,使用您喜欢的前端技术,以及您的用例所需的身份验证机制(例如基于令牌的2FA,SMS 2FA)。

因此,ORY Hydra是最灵活的OAuth 2.0和OpenID Connect提供商,为您提供了实现业务逻辑的极大自由,并且仍然可以从OAuth 2.0和OpenID Connect中获得所有好处。

除了OAuth 2.0功能之外,ORY Hydra还为加密密钥提供安全存储(例如,用于签署JSON Web令牌),并且能够管理OAuth 2.0客户端。

ORY Hydra是OpenID Connect认证(待定),并实现了OpenID Foundation规定的所有要求。因此,它正确地实现了IETF和OpenID Foundation所预期的不同OAuth 2.0和OpenID Connect流程。

ORY Hydra 介绍

Hydra是OAuth 2.0授权框架和OpenID Connect Core 1.0的服务器实现。现有的OAuth2实现通常作为库或SDK。

在不了解整个规范的情况下实现和使用OAuth2具有挑战性,并且即使在使用SDK时也容易出错。Hydra的主要目标是使OAuth 2.0和OpenID Connect 1.0的设置更轻松,更易于使用。

Hydra实现OAuth2和OpenID Connect 1.0中描述的流程,而不强制您使用“Hydra用户管理”或某些模板引擎或预定义的前端。相反,它依赖于HTTP重定向和加密方法来验证用户同意,允许您将Hydra与任何身份验证端点一起使用。

ORY Hydra 不管理用户

要理解的第一个重要概念是ORY Hydra是OAuth 2.0授权和OpenID Connect服务器。有些人将这些功能误认为存储用户数据并将您登录的系统。事实并非如此。相反,此类服务器负责将用户凭据(通常是用户名和密码)“转换”为OAuth 2.0访问和刷新令牌以及OpenID Connect ID令牌。它基本上就像您使用会话数据存储cookie,但更灵活,它也适用于第三方应用程序。

ORY Hydra不存储用户配置文件,用户名,密码。此功能取决于您。ORY Hydra使用我们称之为用户登录和同意流的东西。此流使用HTTP重定向将任何传入的授权请求(“请给我一个访问令牌。”)转发给登录提供者同意提供者。这些应用程序是您实现的。它可以是新应用程序或您现有的登录系统。从较高的层面来看,这些提供商可归纳为:

  • 登录提供者负责通过验证他或她的凭证(例如用户名+密码)来验证用户(“登录”)。
  • 同意提供商负责允许OAuth 2.0应用程序代表用户获取令牌(“您是否希望允许foobar-app访问您的所有个人消息和图像?”。

Ory Hydra OAuth 2.0授权流程:

  1. 开发人员在授权服务器(ORY Hydra)上注册OAuth 2.0客户端,目的是代表用户获取信息。
  2. 应用程序UI要求用户授权应用程序代表他/她访问信息/数据。
  3. 用户被重定向到授权服务器。
  4. 授权服务器确认用户的身份,并要求用户授予OAuth 2.0客户端某些权限。
  5. 授权服务器发出OAuth 2.0客户端用于代表用户访问资源的令牌。

Ory Hydra OAuth 2.0 登录认证网络流程图

1558940908929

我们的OAuth2 实现

1558945515537

角色介绍

  1. 三方平台 (任何想要拿到其他平台授权的应用)

  2. 资源服务器 (我们数据提供端)

  3. 授权服务器 (OAuth2.0 + IDP), 统一授权中心和身份认证中心;

  4. Account Service (基于普通用户的注册,登录,和修改等接口; 另外提供一个公共的OAuth 客户端,三方平台可通过client_id 和 secret 来使用该公共客户端,用来获取授权)

  5. 资源所有者(终端用户)

三方平台接入方法

  1. 先申请 client_id, 和 secret , 之后才可以使用授权服务;
  2. 开发跳转接口, 该接口用来接收终端用户收到的code码, 用来获取access_token等

三方平台授权流程(参考上图)

  1. 调用Account Service 获取授权平台地址并请求;
  2. 用户验证身份通过,并同意授权;
  3. 通过跳转(需提前开发好跳转接口),拿到授权得到的code;
  4. 调用Account Service (使用授权code), 获取access_token 等;
  5. 之后便可使用access_token, 调用资源服务器授权范围内的数据;
刘小恺(Kyle) wechat
如有疑问可联系博主