- RFC 6749
- 四种授权模式
- 授权码(authorization-code)
- 隐藏式(implicit)
- 密码式
- 凭证式(client credentials)
OAuth是目前最流行的授权机制,用来授权第三方应用,获取用户数据,凭借token令牌,在第三方应用进行操作。 RFC 6749
RFC 6749详细介绍了OAuth是什么
首先OAuth引入了一个授权层,用来实现OAuth 的核心就是向第三方应用颁发令牌
通常来说有以下几种角色
Resource owner(资源拥有者) 拥有该角色的最终用户,有访问该资源的账号密码
Resource server (资源服务器) 访问资源的入口,如果请求有正确的令牌,可以授权访问资源
Client (客户端) 访问资源的客户端,需要拿到令牌获取资源,可以是浏览器或者移动设备。
Authorization server(授权服务器) 用于用户授权的服务器,如果客户端授权通过,发放访问资源服务器的令牌
- 授权码(authorization-code)
- 隐藏式(implicit)
- 密码式(password)
- 客户端凭证(client credentials)
不管哪一种授权,都需要第三方应用给对应的资源服务器备案,说明自己的身份,客户端ID和密钥,这是为了令牌被滥用,没有备案是不可能拿到令牌的
授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。这是最常用的流程,安全性也是最高,适用于有后端,也有前端的web应用
-
第一步,A网站提供一个链接,用户点击后会跳转B网站,授权用户登录,用户登录后授权用户数据给A网站,下面是A跳转B网站的一个示意链接
https://b.com/oauth/authorize? response_type=code &client_id=CLIENT_ID& redirect_uri=CALLBACK_URL& scope=read[response_type]:表示是要求返回授权码
[client_id]: 表示身份,让B知道是谁在请求
[redirect_uri] : B授权或者拒绝授权跳转后的地址
[scope]: 权限,B授权A什么权限,或者说A向B获取什么权限,这里应该是只读权限 -
用户跳转B登录后,询问是否给A授权,同意授权后会跳转[redirect_uri],并且带上一个code,类似于
https://a.com/callback?code=AUTHORIZATION_CODE
code 就是授权码 -
客户端拿到授权码后,就会在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_secret] 是每个第三方应用的秘钥,不能泄漏,所以只能给自己的后端去请求
[grant_type]参数的值是AUTHORIZATION_CODE,表示采用的授权方式是授权码
[code]就是上一步拿到的code
[redirect_uri]参数是令牌颁发后的回调网址 -
B 网站收到请求以后,就会颁发令牌。具体做法是向redirect_uri指定的网址,发送一段 JSON 数据
{
"access_token":"ACCESS_TOKEN",
"token_type":"bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN",
"scope":"read",
"uid":100101,
"info":{...}
}
隐藏式(implicit)
这种场景是适配应用没有后端,只有前端,这种方案允许直接将令牌存在前端,所以没有授权码这个步骤。
- A提供一个链接,要求用户跳转B,要求B应用授权给A用户使用
https://b.com/oauth/authorize? response_type=token& client_id=CLIENT_ID& redirect_uri=CALLBACK_URL& scope=read
[response_type]:要求B返回令牌token - 用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回redirect_uri参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站。
注意,令牌的位置是 URL 锚点(fragment),而不是查询字符串(querystring),这是因为 OAuth 2.0 允许跳转网址是 HTTP 协议,因此存在"中间人攻击"的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险。
这种直接给前端的令牌,存在不安全,只能适用于安全性不高的场景,并且令牌的过期时间要足够的短。
密码式如果你高度信任某个应用,RFC6749允许用户把账号和密码告诉第三方应用,以密码的形式去申请令牌,这种叫做密码式
- A网站要求用户输入B网站的账号和密码,拿到以后,向B申请令牌
https://oauth.b.com/token? grant_type=password& username=USERNAME& password=PASSWORD& client_id=CLIENT_ID - B网站验证账号密码的正确性,然后给出令牌,令牌存在一个JSON中,返回给A,注意,这里不是通过跳转连接返回给A的,而是直接放在请求返回体中。
这种适用于没有前端的场景,
- A应用向B发起请求
https://oauth.b.com/token? grant_type=client_credentials& client_id=CLIENT_ID& client_secret=CLIENT_SECRET
上面 URL 中,[grant_type]参数等于[client_credentials]表示采用凭证式,[client_id]和[client_secret]用来让 B 确认 A 的身份。 - B应用校验client_id和client_secret,通过放回令牌,这个令牌是给应用的,多个用户可以拥有同一个令牌
- A应用请求B应用,需要每个请求带上Authorization,B应用校验才能通过
- 如果令牌过期了,重复上述流程体验会很不好,所以,这种方式提供令牌续约。如果A向B发起
https://b.com/oauth/token? grant_type=refresh_token& client_id=CLIENT_ID& client_secret=CLIENT_SECRET& refresh_token=REFRESH_TOKEN
[refresh_token]:之前的令牌,B网站如果验证通过,会颁发一个新的令牌



