开篇
OAUTH 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 OAUTH 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 OAUTH 是安全的。OAuth 是 Open Authorization 的简写。 – _摘自 _百度百科
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. – _摘自 _OAuth2.0 RFC6749 协议
OAuth 2.0 授权框架允许第三方应用程序获得对 HTTP 服务的有限访问,可以代表资源所有者组织、资源所有者和 HTTP 服务之间的审批交互,也可以允许第三方应用程序代表自己获得访问。这个规范取代了RFC 5849中描述的 OAuth 1.0 协议。 – 译文
实际场景分析
- 需求:用户不需要在 M 平台填写注册信息,直接使用微信账号登陆,M 平台通过微信服务方获取到用户的相关信息。
- 闲聊:使用微信账号登陆,总不能把微信的账号密码告诉这个平台吧,万一 M 平台被攻陷,太危险了,用户只想告诉给 M 平台一些基础的用户信息
- 方案:由微信方提供一个凭据,用户进行授权后发放给 M 平台,M 平台通过这个凭据访问微信服务器来获取用户的信息,这就是 OAuth2.0
OAuth2.0 核心
OAuth addresses these issues by introducing an authorization layer and separating the role of the client from that of the resource owner. In OAuth, the client requests access to resources controlled by the resource owner and hosted by the resource server, and is issued a different set of credentials than those of the resource owner.
OAuth 通过引入> 授权层> 并将> 客户端> 角色与> 资源所有者> 角色分离来解决这些问题。在 OAuth 中,客户端请求访问由资源所有者控制并由> 资源服务器> 托管的资源,并被颁发一组不同于资源所有者的> 凭据> 。 – _译文 摘自 _OAuth2.0 RFC6749 协议
- authorization layer:授权层,将客户端角色与资源所有者角色分离
- client:客户端,即 M 平台
- resource owner:资源所有者,即 用户
- resource server:资源服务器,负责存储用户资源属性(用户信息等),即 微信服务器
- authorization server:认证服务器,负责认证并颁发凭据,即 微信服务器
- user agent:用户代理,通过这个代理可访问 M 平台,如 浏览器
Protocol Flow 协议流程解析
Abstract Protocol Flow
Authorization Code Flow (授权码模式)
最安全的一种模式。一般用于 client 是 Web 服务器端应用或第三方的原生 App 调用资源服务的时候。因为在这种模式中 access_token 不会经过浏览器或移动端的App,而是直接从服务端去交换,这样就最大限度的减小了令牌泄漏的风险。
A2 请求参数说明
A2 请求参数说明 | ||
---|---|---|
请求参数名 | 是否必须 | 说明 |
response_type | 是 | 授权类型(授权码模式为:code) |
client_id | 是 | 客户端ID |
redirect_uri | 否 | 重定向URI |
scope | 否(默认全部权限) | 申请的权限范围 |
state | 否 | 客户端当前状态,可指定任意值,认证服务器会原封不动返回 |
C 响应参数说明 | ||
code | 是 | 一次性授权码,有效期很短,与客户端ID和重定向URI是一一对应关系 |
state | 否 | 取决于请求参数是否包含,包含则必定返回原值 |
A2 请求示例
curl -X GET “http://127.0.0.1:10010/oauth/authorize?response_type=code&client_id=c1&redirect_uri=http://www.baidu.com”
-H “accept: /”
-H “Authorization: Basic MTc2MTQ4Mjg1MDA6MTIz”
A2 响应示例
HTTP/1.1 302 Found
Location: https://www.baidu.com/?code=yMBFiJ
D 请求参数说明
D 请求参数说明 | ||
---|---|---|
请求参数名 | 是否必须 | 说明 |
grant_type | 是 | 授权模式(授权码模式为:authorization_code) |
code | 是 | 步骤 C 得到的授权码 |
redirect_uri | 是 | 重定向URI |
E 响应参数说明 | ||
access_token | 是 | 访问令牌 |
token_type | 是 | 令牌类型:bearer or mac |
refresh_token | 是 | 刷新令牌所需 |
expires_in | 是 | 令牌过期时间 |
scope | 是 | 权限范围 |
jti | 是 | 全称:JWT ID,用于防止 Token 被再一次传播 |
D 请求示例
curl -X POST “http://127.0.0.1:10010/oauth/token”
-H “accept: /” -H “Content-Type: application/x-www-form-urlencoded”
-H “Authorization: Basic YzE6NDU2”
-d “{“grant_type”:“authorization_code”,“code”:“yMBFIJ”,“redirect_uri”:“http://www.baidu.com”}”
D 响应示例
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
“access_token”: “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.afdjsafofjdefefewkzn.Nk2_tWZFQgtsE5fUmOgVXzVdOBIl4fOkR2_fTeoE29U”,
“token_type”: “bearer”,
“refresh_token”: “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.JpdGllcyI6WyJwI6IjI5OY3MyZiNTJlMyIsImNsaWVudF9pZCI6ImMxIn0.mWoIpnV0cfR9Mx4Eyz4Kati10yNnG_QuHjrlJdKoKus”,
“expires_in”: 71999,
“scope”: “all”,
“jti”: “69aef4c3-aacb-4f30-abcc-8b2b4aa154c8”
}
Implicit Grant Flow(简化模式)
直接向认证服务器申请令牌,无需经过客户端认证
请求参数说明 | ||
---|---|---|
请求参数名 | 是否必须 | 说明 |
response_type | 是 | 授权类型(简化模式为:token) |
client_id | 是 | 客户端ID |
redirect_uri | 否 | 重定向URI |
scope | 否 | 权限范围 |
state | 否 | 客户端状态 |
响应参数说明 | ||
access_token | 是 | 访问令牌 |
token_type | 是 | 令牌类型:bearer or mac |
refresh_token | 是 | 刷新令牌所需 |
expires_in | 是 | 令牌过期时间 |
scope | 是 | 权限范围 |
jti | 是 | 全称:JWT ID,用于防止 Token 被再一次传播 |
请求示例
curl -X GET “http://127.0.0.1:10010/oauth/authorize?response_type=token&client_id=c1&redirect_uri=http://www.baidu.com”
-H “accept: /”
-H “Authorization: Basic MTc2MTQ4Mjg1MDA6MTIz”
响应示例
HTTP/1.1 302 Found
Location: https://www.baidu.com/#access_token=eyJhbGciOiJmdoaxVJOm&token_type=bearer&expires_in=7200&scope=all&jti=7e1596aa-c02-4cb
注意
响应链接里参数的拼接是在
#
后面而不是常规的?
让不支持 HTTPS 的服务器也能相对安全做第三方登录,浏览器发起一个请求时,地址栏里
#
以及后面部分都是不会随请求发送到服务器的,由于 HTTP 无法防止中间人攻击,access_token 很容易被偷走,所以 Implicit 返回的数据放在#
后面,就是为了防止设备和第三方服务器之间的线路出现 access_token,而只让用户设备拥有 access_token
Resource Owner Password Credentials Grant Flow(密码模式)
用户将自己的账号密码暴露给客户端,客户端使用账号密码向认证服务器申请令牌。
当前操作环境必须安全,需要用户对客户端有充分的信任,否则极度不安全。
B 请求参数说明
B 请求参数说明 | ||
---|---|---|
请求参数名 | 是否必须 | 说明 |
grant_type | 是 | 授权模式(密码模式为:password) |
username | 是 | 用户名 |
password | 是 | 用户密码 |
scope | 否 | 权限范围 |
C 响应参数说明 | ||
access_token | 是 | 访问令牌 |
token_type | 是 | 令牌类型:bearer or mac |
refresh_token | 是 | 刷新令牌所需 |
expires_in | 是 | 令牌过期时间 |
scope | 是 | 权限范围 |
jti | 是 | 全称:JWT ID,用于防止 Token 被再一次传播 |
请求示例
curl -X POST “http://127.0.0.1:10010/oauth/token”
-H “accept: /” -H “Content-Type: application/x-www-form-urlencoded”
-H “Authorization: Basic YzE6NDU2”
-d “{“grant_type”:“password”,“username”:“zhangsan”,“password”:“123”}”
响应示例
参照授权码模式的响应示例
Client Credentials Grant Flow(客户端模式)
脱离用户的范畴,单以客户端的名义向认证服务器申请令牌
请求示例
curl -X POST “http://127.0.0.1:10010/oauth/token”
-H “accept: /” -H “Content-Type: application/x-www-form-urlencoded”
-H “Authorization: Basic YzE6NDU2”
-d “{“grant_type”:“client_credentials”}”
响应示例
参照授权码模式的响应示例
Refresh Token(刷新令牌)
当前 Token 过期后,可使用 refresh_token 重新获取 Token
请求示例
curl -X POST “http://127.0.0.1:10010/oauth/token”
-H “accept: /” -H “Content-Type: application/x-www-form-urlencoded”
-H “Authorization: Basic YzE6NDU2”
-d “{“grant_type”:“refresh_token”,“refresh_token”:“eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.JpdGllcyI6WyJwI6IjI5OY3MyZiNTJlMyIsImNsaW”}”
响应示例
参照授权码模式的响应示例
Oauth2.0 系列文章
以下是同步到语雀的、可读性好一点,优快云 继续看的点专栏就好。
Oauth2.0 核心篇
Oauth2.0 安全性(以微信授权登陆为例)
Oauth2.0 认证服务器搭建
Oauth2.0 添加验证码登陆方式
Oauth2.0 资源服务器搭建
Oauth2.0 自定义响应值以及异常处理
Oauth2.0 补充