參考:
-
從密碼到token, 一個授權的故事
-
理解OAuth 2.0
-
小程序官方文檔
-
微信小程序之登錄態維護(十一)
微信的登陸認證方式跟Oauth的授權碼認證模式非常相似,接下來我大致講解Oauth的三種常用模式以及與微信登陸認證的關聯。
Oauth的三種常用模式
密碼模式

密碼模式的登陸方式大致如上,實際場景里,當用戶在登陸掘金客戶端的時候,可以選擇github認證登陸,而不是直接賬號密碼登陸時。如果這個時候掘金客戶端允許用戶直接在上面輸入賬號密碼,那么客戶端在用戶點擊登陸時,將輸入的信息轉發至github授權服務器上請求授權登陸。如果github服務器授權通過,會返回成功登陸信息,同時我們也成功登陸客戶端。
另外在上面整個過程里,掘金客戶端不允許保存用戶的密碼。
對應的登陸請求如下:
//客戶端直接帶上賬戶名、密碼訪問授權服務器
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
授權服務器返回的信息如下:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
這是第一種Oauth認證方式,這種認證方式其實是用戶在客戶端直接錄入授權賬號和密碼,由客戶端直接發起對授權服務器的登陸認證,其中客戶端不允許保存密碼。
相對應的,這種認證最大的缺點就是用戶賬號密碼全部記錄在客戶端的前端界面,通過請求傳輸給授權服務器,整個過程里密碼容易泄露,安全性差
簡化模式

接著,我們來看第二種認證模式。相比上面那種直接在客戶端輸入賬號密碼的方式,我們轉換下思路,在授權登陸的時候,客戶端帶上之前在授權服務器里注冊過的AppId、AppSecret和登陸成功后的重定向URI,直接訪問對應的授權服務器。授權服務器接收請求,轉至登陸認證界面。
用戶在授權服務器的認證中心下進行賬號密碼的錄入,點擊登陸時,授權服務器通過AppId和App_Secret來識別客戶端,如果識別通過,將token通過hash fagment的形式附著在重定向地址上,返回給客戶端。
在整個過程里,客戶端都不接觸用戶名和密碼,只需要保存授權服務器返回的token,在后續的API請求里帶上token即可。
客戶端發起的請求如下:
//客戶端需要帶上注冊過的id、重定向地址,也可以帶上對應的密鑰
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
授權服務器返回的信息:
//授權服務器的token通過#號隔開,直接附著在地址上
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
&state=xyz&token_type=example&expires_in=3600
這種方式最大的缺點是token通過重定向地址直接返回客戶端,安全性差,容易被人通過瀏覽器的歷史記錄或者訪問日志里竊取
授權碼模式

基于第二種模式里,token是直接通過URL地址返回給客戶端導致安全性差的問題,那么我們可以變通一下,在授權服務器重定向至客戶端時,不要直接帶上token,帶上某個特殊的授權碼code表示服務器已經同意授權認證。
接著讓客戶端的服務器后臺發起請求,把客戶端在授權服務器里注冊過的AppId、AppSecret、接收的授權碼code帶上,由授權服務器通過Id和Secret密鑰對code進行解密驗證,如果驗證通過表示當前請求的客戶端是正確的,接著再返回實際的token給客戶端即可。
客戶端第一次發起的請求:
//客戶端第一次發起請求,帶上id和重定向地址
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
授權服務器返回的信息:
//授權服務器登陸認證通過,返回對應的授權碼code
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
客戶端第二次發起的請求:
//客戶端第二發起的請求,帶上id、secret和重定向地址
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
授權服務器最終返回的信息:
//返回對應的token
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
授權碼認證模式里授權服務器不直接返回token,而是返回授權碼,由開發者服務器帶上相關信息后臺發送請求,授權服務器進行單獨的授權認證之后才返回token。通過兩次請求再返回token,保證了安全性。
微信認證方式

微信的登陸認證方式,其實跟授權碼模式很相似,區別在于簡化了獲取授權碼code的過程,不需要帶上賬號密碼,調用wx.login就可以從微信服務器上返回授權碼,并且整個過程不需要繁瑣地重定向,通過后臺請求就可以獲取token。
這四種認證方式對應的關系如下圖所示:
