-
是什么?
目前最流行的授权机制,用来授权第三方应用,获取用户数据
-
为什么出现?
- 用户体验优化:如果用户登录的某个应用,此时还想使用另一个应用,用户只需要授权,无需再输入账户密码即可进入第三方应用。
- 安全:授权后,应用可知晓调用方来源
-
授权流程是什么?
数据的所有者(比如我的信息)告诉系统(微信),允许第三方应用(QQ)进入系统,获取这些数据。系统产生一个短期的access_token 令牌,来代替用户名密码,供第三方应用进入应用获取我的数据。
-
令牌设计 和 密码对比
- 密码。相当于第三方,完全掌控了 授权人 在系统中的所有权限,第三方可任意时间进入系统,可进入授权人不想授权的访问数据范围。
- 令牌
- 授权时间的控制
- 令牌是有时效性。一般防止令牌泄漏的风险,令牌的有效期设置的很短。
- 授权发放和撤销的控制
- 权限范围控制
- 只读 & 读写
- 授权时间的控制
-
授权方式- authorization grant
-
授权码模式(authorization-code)
大致流程:第三方首先申请到一个授权码,之后通过授权码换取token
-
特点
- 安全性最高
- 授权码通过前端传送,令牌存储在后端
适用系统:有后端的web应用
-
细致流程
-
A 网站提供一个链接,用户点击后就会跳转到 B 网站,授权用户数据给 A 网站使用。下面就是 A 网站跳转 B 网站的一个示意链接。
参数
https://b.com/oauth/authorize? response_type=code&. // 表示要求返回授权码(code) client_id=CLIENT_ID& // 表示a的身份 redirect_uri=CALLBACK_URL& // B 接受或拒绝请求后的跳转网址 scope=read // 表示要求的授权范围(这里是只读)
-
用户跳转后,B 网站会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回
redirect_uri
参数指定的网址。跳转时,会传回一个授权码,就像下面这样https://a.com/callback?code=AUTHORIZATION_CODE // code参数就是授权码
-
A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。
https://b.com/oauth/token? client_id=CLIENT_ID& client_secret=CLIENT_SECRET& //client_id参数和client_secret参数用来让 B 确认 A 的身份(client_secret参数是保密的,因此只能在后端发请求) grant_type=authorization_code& // 表示采用的授权方式是授权码 code=AUTHORIZATION_CODE& redirect_uri=CALLBACK_URL // 参数是令牌颁发后的回调网址
-
B 网站收到请求以后,就会颁发令牌。具体做法是向
redirect_uri
指定的网址,发送一段 JSON 数据。{ "access_token":"ACCESS_TOKEN", // 令牌 "token_type":"bearer", "expires_in":2592000, "refresh_token":"REFRESH_TOKEN", // 令牌过期后,可用此token申请更新 "scope":"read", "uid":100101, "info":{...} }
-
-
隐藏式(implicit)
适用系统:纯前端应用
-
特点:
- 无授权码中间步骤
- 很不安全。所以必须要求令牌的有效期必须非常短,通常就是会话期间(session)有效,
-
详细步骤
-
A 网站提供一个链接,要求用户跳转到 B 网站,授权用户数据给 A 网站使用。
https://b.com/oauth/authorize? response_type=token& client_id=CLIENT_ID& redirect_uri=CALLBACK_URL& scope=read
-
用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回
redirect_uri
参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站https://a.com/callback#token=ACCESS_TOKEN
注意,令牌的位置是 URL 锚点(fragment)即url “#” 后面的,而不是查询字符串(querystring)即?后面的,这是因为 OAuth 2.0 允许跳转网址是 HTTP 协议,因此存在"中间人攻击"的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险
解释:锚点 - 主要资源是由 URI 进行标识,URI 中的 fragment 用来标识次级资源。在 URI 的末尾通过 hash mark(#)作为 fragment 的开头,其中 # 不属于 fragment 的值。
-
-
密码式(password)
-
特点:
- 用户高度信任第三方应用
- 风险很大
-
流程
-
A 网站要求用户提供 B 网站的用户名和密码。拿到以后,A 就直接向 B 请求令牌
https://oauth.b.com/token? grant_type=password& // 授权方式 密码式 username=USERNAME& password=PASSWORD& client_id=CLIENT_ID
B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 因此拿到令牌
-
-
-
客户端凭证式(client credentials)
-
适用:
- 没有前端的命令行应用
- 是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。 -- 接口安全验证
一般saas系统会用到
-
-
流程
-
A 应用在命令行向 B 发出请求。
https://oauth.b.com/token? grant_type=client_credentials& // 表示采用凭证式 client_id=CLIENT_ID& // B 确认 A 的身份 client_secret=CLIENT_SECRET // B 确认 A 的身份
B 网站验证通过以后,直接返回令牌。
之后,A网站每次请求B网站,带着此令牌即可来表明身份。一般还会进行验签,保证安全
-
-
-
令牌的使用
A 网站拿到令牌以后,就可以向 B 网站的 API 请求数据了。
-
具体做法:在请求的头信息,加上一个
Authorization
字段curl -H "Authorization: Bearer ACCESS_TOKEN" \ "https://api.b.com"
上面命令中,
ACCESS_TOKEN
就是拿到的令牌。
-
更新令牌
令牌的有效期到了,如果让用户重新走一遍上面的流程,再申请一个新的令牌,很可能体验不好,而且也没有必要。OAuth 2.0 允许用户自动更新令牌。
具体方法是,B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(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
B 网站验证通过以后,就会颁发新的令牌。
参考: