參考:
微信的登陸認證方式跟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。
這四種認證方式對應的關係如下圖所示: