为什么
关于OAuth
出现的背景, 在上一篇OAuth1.0介绍 中已经写过了, 而2.0
的提出必然是为了解决1.0
中出现的问题. 感兴趣的可以去看看.
2.0
针对1.0
的问题提出了解决方案, 将协议升级为HTTPS
同时取消了secret
加密签名. 对非 web 应用也进行了支持.
介绍
OAuth
是什么呢? 在RFC 文档中是这样介绍的.
The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf. This specification replaces and obsoletes the OAuth 1.0 protocol described in RFC 5849.
写的比较官方哈, 简单说, 就是授权他人以拥有临时访问资源的权限.
实现
先简单介绍授权过程中涉及到的几个角色:
- 客户端: 既需要申请资源的应用
- 资源拥有者: 既用户
- 授权服务器: 通过此服务器获取权限
- 资源服务器: 通过此服务器进行资源的操作
授权流程
在授权之前, 客户端需要先到服务器进行备案, 并拿到身份标识:
- client_id: 用于客户端身份标识
- client_secret: 用于对请求内容进行签名
整个授权流程如下(截图自 RFC 文档):
其中各个步骤的简单说明:
- 客户端向用户申请权限
- 用户同意进行授权
- 客户端拿着获得的用户授权, 向授权服务器申请权限令牌
- 授权服务器通过验证后, 发放权限令牌
- 客户端时候令牌, 向资源服务器申请资源
- 资源服务器验证通过后, 返回资源
其中的授权服务器和资源服务器只是概念上的拆分, 在实际中可以是同一个服务器(个人感觉这个拆分么的什么用呀).
整个过程使用HTTPS
协议进行通信. 其中3-6步, 只是简单的HTTPS
请求, 其中比较关键的部分就是用户如何同意授权.
授权模式
在1.0
版本中, 用户的授权是到资源服务器登录并同意授权后, 再通过回调接口的方式通知客户端成功授权的. 当时存在的问题是对非 web 应用不友好. 而在2.0
版本中, 为了应对多种场景, 给出了四种不同的授权模式.
授权码
授权码模式就是客户端先拿到一个授权码, 然后使用授权码到授权服务器获取授权令牌. 与1.0
的授权方式差不多.
这里就不用 RFC 文档中的图了, 换一张我画的感觉更简洁一些.
看这个流程, 其实和1.0
版本的流程差不多. 对以上几步简单说明.
1. 重定向到服务器授权页面
将用户引导到授权服务器进行授权操作.
携带参数
- response_type: 请求类型, 值为 code, 标识为授权码模式
- client_id: 客户端 ID. 用于标识客户端身份
- redirect_uri: 用户授权成功后, 通知的回调链接.
- scope: 用于标识需要申请的权限.
2. 用户在 授权服务器完成授权操作
用户在授权服务器页面进行登录授权.
3. 将页面重定向到事先指定的链接, 带上授权 code
用户授权完成后, 授权服务器将页面重定向到第一步中的redirect_uri
, 通知客户端授权结果. 在进行跳转时会带上授权成功后的授权码.
4. 使用授权 code 获得令牌 access_token
用户成功授权并拿到授权凭证后, 想授权服务器申请access_token
.
携带参数
- client_id
- client_secret: 因为当前请求是由后端发起, 不会经过客户端, 因此不会泄露.
- grant_type: 授权方式. authorization_code(表示授权码)
- code: 上一步获取的授权码
到这一步, 已经完成整个授权流程.
简化版
有些网站是纯前端的, 没有后端. 这种方式直接向前端颁发授权令牌, 省去了授权码这个步骤.
1. 重定向到服务器授权页面
将用户引导到授权服务器进行授权操作.
携带参数
- response_type: 请求类型, 值为 token, 表示直接返回token
- client_id: 客户端 ID. 用于标识客户端身份
- redirect_uri: 用户授权成功后, 通知的回调链接.
- scope: 用于标识需要申请的权限.
2. 用户在 授权服务器完成授权操作
用户授权操作没有什么差别.
3. 将页面重定向到回调链接并携带授权 token
因为没有后端服务器, 因此授权成功后直接在重定向链接中带有授权 token. 链接形式: https://test.com/callback#token=ACCESS_TOKEN
注意, 这里access_token
是以锚点的形式拼在回调链接上的. 因为浏览器在访问的时候, 不会将锚点发送, 因此可以避免中间人攻击.
以这种方式获取的令牌往往授权时间比较短, 通常就是 session 期间有效.
密码版
这就是原始的版本了, 将你的用户名和密码直接告诉客户端, 然后客户端使用你的密码去申请令牌.
客户端获取 token 时携带的参数如下:
- grant_type: 授权类型. (password)
- username
- password
- client_id
- scope
授权服务器校验后会返回授权令牌. 注意, 一般在第一步获取用户名和密码时, 客户端并不对其进行存储, 仅仅是在第二步获取授权时使用.
客户端模式
适用与没有交互界面的应用. 授权过程中没有用户参与, 客户端直接申请 token.
携带参数
- grant_type: 授权类型(client_credentials)
- client_id
- client_secret
授权服务器校验后直接返回access_token
. 看这个模式并不是OAuth
想要解决的问题啊, 看不懂为什么放在这里
令牌更新
OAuth2.0
允许在令牌过期后, 不经过用户进行令牌的更新. 授权服务器在颁发令牌时, 会同时颁发两个令牌: access_token
refresh_token
.
其中refresh_token
的过期时间要更久一些, 用于当access_token
过期后对其进行更新.