授权码(authorization code)方式:第三方应用先申请一个授权码,然后再用该码获取令牌。
最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。
第一步:A 网站提供一个链接,用户点击后就会跳转到 B 网站,授权用户数据给 A 网站使用。下面就是 A 网站跳转 B 网站的一个示意链接。
https://b.com/oauth2/authorization
response_type=code\ # 表示需要一个授权码
client_id=CLIENT_ID\ # 第三方应用的id
redirect_uri=CALLBACK_URL\ # 完成后的回调地址
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\ # 应用id
client_secret=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","scope":"read","uid":100101,"info":{...}}
# access_token字段就是令牌
二:隐藏式
有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。RFC 6749 就规定了第二种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)"隐藏式"(implicit)。
第一步,A 网站提供一个链接,要求用户跳转到 B 网站,授权用户数据给 A 网站使用。
https://b.com/oauth/authorize?
response_type=token\ #表示期望直接拿到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
# 这是一种很不安全的方式。
三:密码式
如果你高度信任某个应用,允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。
第一步,A 网站要求用户提供 B 网站的用户名和密码。拿到以后,A 就直接向 B 请求令牌。
https://oauth.b.com/token?
grant_type=password\ # 认证方式:账号密码
username=USERNAME\ # user
password=PASSWORD\ # pwd
client_id=CLIENT_ID # 应用id
第二步,B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 因此拿到令牌。
这种方式需要用户给出自己的用户名/密码,风险很大,因此只适用于其他授权方式都无法采用的情况,而且必须是用户高度信任的应用。