前言
1. 什么是OAuth
Oauth(Open Auth)是一个开放的网络授权协议,旨在提供"指定权限的访问"的能力,我们常说的“第三方登陆”、“SSO单点登录”,其内部原理大都涉及OAuth。
比如作为一个第三方App,需要访问你的微信个人信息,这个访问需要微信授权,但实际上你不需要提供你的微信用户名和密码,只是由微信授权提供一个安全的有时限的Access Token(访问令牌),第三方App服务只需要提供这个Access Token即可以达到获取微信个人信息数据;即使第三方存在信息安全泄露问题,微信的用户名账号密码还是安全的。
一个很好的类别: OAuth中的访问Token令牌,类似于高级轿车的代驾钥匙(仅可以用于移动轿车一小段距离提供泊车用,而不能开启后备箱等其他功能),当用户来到酒店时候,酒店服务人员提供泊车服务,需要向用户申请允许移动车辆的泊车钥匙,完成泊车服务;
OAuth不共享密码数据,而是使用授权令牌来证明消费者和服务提供商之间的身份。OAuth是一种身份验证协议,允许您代表您批准与另一个应用程序交互的应用程序,而不会泄露您的密码,其关键技术在于访问Token令牌的申请过程。
OAuth涉及三方:用户、消费者(第三方应用)、服务提供方,用户授权服务提供方,提供一个令牌给到服务消费方,来完成服务消费;
2. 工作流解说1:(用户在得到看到一个好的课程,准备分享到微信朋友圈)
2.1. 第一步,用户意图
- Alice(用户):“嘿,得到,我想分享这本书到我的微信朋友圈!”
- 得到(消费者):“好的,让我去找微信授权下!”
2.2. 第二步,服务消费者申请获取授权码/请求Token
- 得到(消费者):“微信,我这边有个用户需要分享他的内容到朋友圈,可以申请一个**请求Token(授权码)**么?”
- 微信(服务提供方):“好的,这个是请求Token令牌和一个请求签名秘钥,你让用户确认下”
该请求签名秘钥用于防止CSRF请求伪造,消费者使用密钥对每个请求进行签名,以便服务提供者可以验证它实际上来自消费者应用程序。
2.3. 第三步,用户被重定向到服务提供方
- 得到:”OK,Alice,我要把你送到微信授权下,拿着这个请求Token
- Alice:“好的”
这一步存在被钓鱼的情况,恶意网站可能会伪造一个微信钓鱼站点,让你输入微信的账号、密码等。
2.4. 第四步,用户授权
- Alice:“微信,我想批准得到获取请求Token,你帮授权下”
- 微信:“好的,你这边准备授权得到 - 获取Alice“分享朋友圈”的权限么?
- Alice:“是的,我授权得到拥有使用微信分享Alice朋友圈的权限”
- 微信,“好的,微信已授权该请求Token令牌,拥有分享Alice朋友圈的权限,请告知得到”
2.5. 第五步,消费者活动访问令牌
- 得到:“微信,我可以使用这个请求Token获取**访问token(Access Token)**么?”
- 微信:“当然,这是你的访问token和秘钥”
2.6. 第六步,消费者访问受保护的资源
- 得到:“微信,我想把这个链接分享到朋友圈,这是我的访问token令牌”
- 微信:“好的,访问Token令牌验证正确,分享内容到Alice朋友圈了"
3. 工作流解说2:(A网站获取Github用户基本数据)
- A 网站让用户跳转到GitHub。
- GitHub 要求用户登录,然后询问"A 网站要求获得 xx 权限,你是否同意?"
- 用户同意,GitHub 就会重定向回 A 网站,同时发回一个授权码。
- A 网站使用授权码,向 GitHub 请求令牌。
- GitHub 返回令牌.
- A 网站使用令牌,向 GitHub 请求用户数据。
4. OAuth 1.0与OAuth 2.0 差别
- OAuth 2.0是OAuth协议的下一版本,但不向下兼容OAuth 1.0(如果您今天创建新应用程序,请使用OAuth 2.0)。
- OAuth 2.0关注客户端开发者的简易性,同时为Web应用、桌面应用、手机和智能设备提供专门的认证流程,更快,更容易实现。
- OAuth 2.0有六个流程用于不同类型的应用程序和要求(梳理下来有四类Access Token授权方式),OAuth令牌不再需要在2.0中的端点上加密,因为它们在传输过程中已加密(通过HTTPS启用签名机制)。
5. OAuth 2.0四类用户授权方式
虽然说四类,官方文档实际指明六授权类型,除下面四类:(授权码、隐式、密码、凭据)外,还有包括另外两类:(设备码、刷新token),我们这边指明与用户授权相关更紧密一些的,单独指明四类场景,刷新token是作为过期机制,设备码(web应用中开发中)涉及较少。
5.1. 前后端授权码方式 - 最常用,安全系数高
指的是第三方应用先申请一个授权码,然后再用该码获取令牌。(上面Alice、得到、微信的示例中,请求Token其实就是授权码,这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。)
|
|
5.2. 纯前端隐藏式 - 安全要求不高、token时效短的场景
针对纯前端应用,RFC6749 就规定了第二种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit)。
令牌的位置是 URL 锚点(fragment),而不是查询字符串(querystring),这是因为 OAuth 2.0 允许跳转网址是 HTTP 协议,因此存在"中间人攻击"的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险。
|
|
5.3. 纯后端凭证式 - 内部系统交互用
最后一种方式是凭证式(client credentials),适用于没有前端的命令行应用,即在命令行下请求令牌。
|
|
5.4. 密码代理式 - 较少用
如果你高度信任某个应用,RFC6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请并获取令牌,这种方式称为"密码式"(password)。
|
|
6. 访问令牌使用
6.1. 基于令牌请求服务
|
|
6.2. 基于刷新令牌,在过期前刷新token
OAuth 2.0 允许自动更新令牌(没有必要再重新走一次用户授权流程)。
服务提供者在提供请求Token(授权码)时候,会提供额外一个刷新Token,这样服务消费者(第三方应用)可以在令牌过期前,更新访问令牌(Access Token)。
|
|
7. 完整的Github示例参考
参见:http://www.ruanyifeng.com/blog/2019/04/github-oauth.html
8. 针对Token和Token的管理
最长见到的就是,JWT令牌(RFC 7519),JSON网络令牌(JWT)是JSON的基于开放标准,用于创建访问令牌(Access Token),JWT被设计为紧凑以及URL-safe
。
JWT依赖于其他基于JSON的标准:JWS(JSON Web签名)RFC 7515和JWE(JSON Web加密)RFC 7516。
8.1. JWT结构
JWT的结构由头、有效载体、签名3部分组成。头包含签名算法、类型,有效载体包含一组常规+自定义的声明,签名部分通过Base64url Encoding对标头和有效负载进行编码,并将它们与句点分隔符连接在一起来计算签名。
签名在Chrome上面,可以基于JWT Debugger
工具进行验签。
|
|
8.2. 请求头标准字段
- typ: token类型,必须为
JWT
- cty: 内容类型,可以忽略,用于嵌套签名或加密
- alg: 签名算法
8.3. 有效载体中的标准字段
- iss: 签发者
- sub: 标识jwt主题
- aud: 标识JWT的消费者
- exp: 标识JWT过期时间,时间戳格式
- nbf: 标识JWT不早于指定时间,时间戳格式
- iat: 标识JWT签发时间,时间戳格式
- jti: JWT ID,在不同的发行者之间,令牌的区分大小写的唯一标识符
8.4. JWT使用
在身份验证中,当用户使用OAuth成功授权后,返回的JWT令牌,并且必须在本地保存(通常在本地或会话存储中,但也可以使用cookie),而不是传统的创建会话的方法在服务器中并返回一个cookie。
每当用户想要访问受保护的路由或资源时,用户代理应该Authorization使用Bearer模式发送JWT,通常在头部中。标头的内容可能如下所示:
|
|
这是一种无状态身份验证机制,因为用户状态永远不会保存在服务器内存中。服务器的受保护路由将在Authorization标头中检查有效的JWT,如果存在,则允许用户访问受保护的资源。由于JWT是自包含的,所有必要的信息都在那里,减少了多次查询数据库的需要。
8.5. GO实现JWT的开源包
参考:https://github.com/dgrijalva/jwt-go
9. 参考
- OAuth官档:https://oauth.net/2/
- https://www.varonis.com/blog/what-is-oauth/
- https://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
- http://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html
- http://www.ruanyifeng.com/blog/2019/04/github-oauth.html
- JWT wiki:https://en.wikipedia.org/wiki/JSON_Web_Token#cite_note-18
- JWT介绍:https://jwt.io/introduction