目的
本文将介绍OAuth2的来龙去脉以及具体的实现
什么是OAuth2
OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容
比如我们经常在网页或者app登录的时候,可以选择qq,微信,微博等第三方账号登录该系统,qq,微信,微博就是通过实现OAuth2来实现登录这些系统的,并且保证了qq账号,微信账号,微博账号的密码不会被泄露。
与OAuth1有什么区别
OAuth2.0是OAuth协议的延续版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0。所以可以不用管OAuth1.0
示例
有这样一个场景,我在某网盘上保存了一些照片,现在让某个云打印app打印我在网盘上保存的一张照片,并且通过快递寄给我。步骤如下图:
详细步骤:
- 1.用户请求云打印服务
- 2.云打印服务请求用户授权它访问云盘
- 3.用户同意给云服务访问照片的权限
- 4.云打印服务拿着用户给它的访问照片权限去授权服务,获取访问令牌
- 5.授权服务判断权限是否合法,确实是不是用户给的,如果是,则返回访问照片的令牌
- 6.云服务用访问照片令牌去访问云盘
- 7.云盘鉴权token,发现合法,返回照片给云服务
问题:
-
1.为什么要区分用户授权和访问令牌? 答:因为必须要有用户同意并且设置访问权限(查看、编辑、删除等)
-
2.为什么用户授权的时候不直接返回令牌,而需要云服务拿着授权再去授权服务获取令牌? 答:因为令牌有生成规则、有效期、失效等需要管理,因此单独用授权服务来管理。
原理
将上面的示例抽象一下,得到下图:
解释:
- Client:作为访问应用的客户端,也就是需要经过授权才能访问资源的应用程序,在例子中就是第三方应用(云打印)。
- Resource Owner:即资源所有者,例子中的用户,他可以授予第三方应用(云打印)也就是 Client,对受保护资源的访问权限的实体。
- Authorization Server:即授权服务器,其作用是在 Resource Owner 验证并给予 Client 授权后,通过 Authorization Server 向 Client 颁发访问的令牌。
- Resource Server:即资源服务器,它是用来存放资源的,在例子中用来存放电子照片,当 Client 使用令牌访问它的时候,它会接受响应并返回 Resource Owner 所保护的资源,也就是电子照片。
步骤:
- 1.客户端(Client)向资源所有者(Resource Owner)请求授权。
- 2.客户端(Client)收到用户授权,这是代表资源所有者(Resource Owner)授权的凭证(Authorization)。
- 3.客户端(Client)通过与授权服务器(Authorization Server)进行身份验证并提供授权许可来请求访问令牌(Access Token)。
- 4.授权服务器(Authorization Server)对客户端进行身份验证并验证授权许可,如果有效,则颁发访问令牌(Access Token)。
- 5.客户端(Client)向资源服务器(Resource Server)请求受保护的资源并通过提供访问令牌(Access Token)进行身份验证。
- 6.资源服务器(Resource Server)验证访问令牌(Access Token),如果有效,则为请求提供服务。
令牌刷新
令牌有有效期,授权服务会定期调用客户端提供的回调URL让它更新令牌,或者客户端定期调用授权服务来更新令牌,这样就可以保证令牌长时间有效。
授权方式
上述第二步,用户向客户端授权资源访问权限,该如何授权呢?主要有四种方式。
授权码模式
这个模式是最复杂的,也是目前使用最多的。
这里对这一原因进行解释如下:用户代理在显示中都以浏览器的方式存在,而浏览器中对应的重定向 URI(redirect_uri)被认为是不安全信道,此方式不适合敏感数据-访问令牌的传输。
因为 URI 有可能通过 HTTP referrer 传递到其它恶意站点,也可能存在于浏览器 cacher 或 log 文件中,这就给攻击者盗取访问令牌提供了便利。
这里还有一个假设,就是设资源所有者的行为虽然是可信赖的,但是资源所有者所使用的用户代理,也就是浏览器可能早已被攻击者植入了跨站脚本用来监听访问令牌。
此时将访问令牌用户代理传递给客户端,会扩大访问令牌被泄露的风险。但授权码(Authorization Code)是可以通过重定向 URI 来传递的。
授权码并不像访问令牌那样敏感,即使授权码泄露了,攻击者也无法直接拿到访问令牌从而访问资源。因为拿到授权码去交换访问令牌时是需要验证客户端真实身份的。
说白了就是除了客户端之外,其他人拿授权码事没有用的。这也事为什么访问令牌只能发给客户端使用的原因,其他任何主体包括资源所有者都不应该获取访问令牌。
协议的设计保证客户端是唯一有能力获取访问令牌的主体。引入授权码的目的也是为了保证客户端是访问令牌的唯一持有人。
另外,由于协议需要验证客户端的身份,如果不引入授权码,客户端的身份认证只能通过重定向 URI 来传递。
由于重定向 URI 是一个不安全信道,就额外要求客户端必须使用数字签名技术来进行身份认证,而不能用简单的密码或口令认证方式。
引入授权码之后,授权服务器可以直接对客户端进行身份认证,可以支持任意的客户端认证方式。
可以理解为授权码作为客户端和资源所有者之间的中介,用来验证客户端的身份。
隐式授权码模式
隐式授权码模式简化了授权码获取的过程,通过 Web 托管客户资源返回的 Script 脚本中携带了对应的访问码,用户代理在抽取访问码之后返回给客户端调用资源。
这种方式虽然省去了获取授权码的过程,但是在用户代理中存放了访问码存在一定的安全风险。
密码模式
用户向客户端提供自己的用户名和密码。客户端使用这些信息,向授权服务器索要授权。在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。
这通常用在用户对客户端高度信任的前提下才能进行,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。
客户端模式
指客户端以自己的名义,而不是以用户的名义,向授权服务器进行认证。
由于不存在资源所有者的授权行为,因此这种模式严格上来说不属于 OAuth 2.0 的模式范畴。客户端在授权服务器上存在可控资源的情况,才能使用这种方式。
总结
本文从云打印照片的例子开始,通过用户授权云打印服务访问云盘获取电子照片的整个过程,带出了 OAuth 2.0 所实现的资源授权与访问的功能。
然后提出 OAuth 2.0 是用来保证第三方应用授权访问资源安全性的协议,其协议会涉及到客户端、资源所有者、授权服务器和资源服务器,并且描述了授权过程如何在它们之间展开的。
在介绍完授权流程之后,又进一步说明了在过程中获取访问令牌才能访问资源,如果令牌过期的情况下需要通过刷新令牌保持授权的有效性。
最后介绍了 OAuth 2.0 的 4 种授权模式,分别是授权码模式、隐含授权模式、密码模式和客户端模式,以及它们的实现流程。
参考
[1]OAuth2是什么?能干什么?
[2]Oauth2是什么&怎么用
[3]github: osin
[4]什么是 JWT?
[5]什么是JWT
[6]终于有人把OAuth2.0原理讲明白了!
[7]Oauth2详解-介绍(一)