概念
开放授权(OAuth)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。
名词介绍
资源拥有者 (Resource Owner)
客户端 (Client)
资源服务器 (Resource Server)
授权服务器 (Authorization Server)
先举个例子在说
场景:客户想从仓库里面拿走货物
步骤:
与厂长签订合同
拿合同到厂长那,换取发票
那发票到库管那,换取出库单
拿到出库单即可获取货物
对比看一下
分析一波
资源拥有者 (Resource Owner) == 库管
客户端 (Client) == 客户
资源服务器 (Resource Server) == 仓库
授权服务器 (Authorization Server)== 厂长
(A)Authrization Request:用户打开客户端以后,客户端要求用户给予授权。
(B)Authorization Grant(Get):用户同意给予客户端授权。
(C)Authorization Grant(Post):客户端向授权服务器发送它自己的客户端身份标识和上一步中获得的授权(authorization grant),向认证服务器申请令牌。
(D)Access Token(Get):认证服务器对客户端进行认证以后,确认无误,同意发放令牌(access token),授权阶段至此全部结束。
(E)Access Token(Post && Validate):客户端使用令牌,向资源服务器申请获取资源。
(F)Protected Resource(Get):资源服务器确认令牌无误,同意向客户端开放资源。
从整个流程可以看出,在 B 步骤最为关键,即需要获取到用户对客户端的授权(如我们在微信扫码登录时,点击“确定”按钮的步骤)。有了这个授权以后,客户端才能拿到令牌,进而凭令牌向资源服务器获取资源。
示例
微信登录
第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据 code 参数;
通过 code 参数加上 AppID 和 AppSecret 等,通过 API 换取 access_token ;
通过 access_token 进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
四种授权模式
授权码(authorization code)
第三方应用先申请一个授权码,然后再用该码获取令牌。
适用于有后端的 Web 应用,授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。
这种方式也是最常用的流程,安全性最高。
步骤分析
用户从 A 网站跳转到 B 网站,请求用户确认授权,以获取授权码 https://b.com/oauth/authorize?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read 参数详情
response_type 参数表示要求返回授权码(code);
client_id 参数让 B 知道是谁在请求;
redirect_uri 参数是 B 接受或拒绝请求后的跳转网址;
scope 参数表示要求的授权范围(这里是只读);
在 B 网站中,当用户同意授权 A 网站,则 B 网站会携带授权码,重定向到 redirect_uri 参数指定的网址,就像下面这样: https://a.com/callback?code=AUTHORIZATION_CODE
A 网站获取授权码以后,在 A 网站后端中向 B 网站请求令牌: https://b.com/oauth/token?
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=CALLBACK_URL 参数详情
client_id 参数和 client_secret 参数用来让 B 确认 A 的身份( client_secret 参数是保密的,因此只能在后端发请求);
grant_type 参数的值是 AUTHORIZATION_CODE ,表示采用的授权方式是授权码;
code 参数是上一步拿到的授权码;
redirect_uri 参数是令牌颁发后的回调网址;
B 网站接受请求并验证身份,身份验证通过后,会发放令牌。向redirect_uri 指定的网址,发送包含令牌 access_token 字段的JSON数据,流程完毕。
隐藏式(implicit)
即隐藏授权码步骤,直接向前端发放令牌,也称授权码隐藏式。
步骤分析
户从 A 网站跳转到 B 网站,要求授权用户数据给 A 网站使用。 https://b.com/oauth/authorize?
response_type=token&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read 参数详情
response_type 参数为 token,表示要求直接返回令牌。
用户在 B 网站同意授权给 A 网站。 当用户同意授权后,会跳转到 redirect_uri 参数指定的重定向地址,
并将令牌作为 URL 参数传递给 A 网站。
token 参数就是令牌,A 网站因此直接在前端拿到令牌。 https://a.com/callback#token=ACCESS_TOKEN
注意:这里的令牌位置是 URL 锚点(即 # 号),而不是查询字符串,这是因为锚点不会发到服务器,避免泄露令牌的风险。
适用场景:由于直接传递令牌不安全,因此常常适用在对安全要求不高的场景,并且令牌有效期非常短,例如会话期间(session)有效,关闭浏览器便失效。
密码式(password)
即:对于信任的应用,可以携带约定的用户名和密码进行令牌申请。
步骤分析
A 网站使用 B 网站提供的用户名和密码,向 B 网站发起令牌请求。 https://oauth.b.com/token?
grant_type=password&
username=USERNAME&
password=PASSWORD&
client_id=CLIENT_ID
```
grant_type 参数是授权方式,这里的 password 表示"密码式";
username 和 password 是 B 的用户名和密码。
B 网站验证身份后直接将令牌存在 JSON 数据中,作为 HTTP 相应返回令牌给 A 网站。
适用场景:
风险较大,一般适用在对应用高度信任的情况。
客户端凭证(client credentials)
即:给出凭证让对方确认并提供令牌。
步骤分析
A 应用在命令行向 B 发出请求。 https://oauth.b.com/token?
grant_type=client_credentials&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET grant_type 参数等于 client_credentials 表示采用凭证式;
client_id 和 client_secret 用来让 B 确认 A 的身份。
B 网站验证身份后返回令牌。
适用场景:
通过命令行请求令牌。这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。
令牌应用
使用令牌
当网站获取到令牌以后,接下来每个 API 请求都需要带上令牌,其做法是在请求的头信息中,将令牌添加 Authorization 字段中。
更新令牌
当令牌有效期到了,OAuth2 允许用户自动更新令牌,而不用让用户重新授权获取新令牌。
更新流程
在 B 网站发放令牌时,一次性发放 2 个令牌,一个用于获取数据,一个用于获取新的令牌(refresh token 字段)。令牌到期后,用户使用 refresh token 发送请求去更新令牌:
https://b.com/oauth/token?
grant_type=refresh_token&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
refresh_token=REFRESH_TOKEN
grant_type 参数为 refresh_token 表示要求更新令牌;
client_id 参数和 client_secret 参数用于确认身份;
refresh_token 参数就是用于更新令牌的令牌。
B 网站验证通过以后,就会颁发新的令牌。