也許,這樣理解OAuth原理更容易

那一年,我所在公司的用戶量達到了公司成立以來的新高峰,經過多個程序員日日夜夜加班,每個業務系統達到了幾乎四個 9 的穩定性,同時業務在業界也有了一定的知名度。

也許,這樣理解OAuth原理更容易


圖片來自 Pexels

PS:以下業務場景只針對於 Web 系統,而且 Web 頁面有後臺服務程序的場景。

那一天突然有一個合作商登門拜訪,提出合作共贏的意向。業務的場景就是我們的系統用戶能夠在他們系統登錄,並能夠獲取用戶一定的信息以便進行一些業務操作。

他們希望我們能夠把已存在的用戶數據 Copy 一份導入他們的系統,並且新註冊的用戶進行單項同步更新。這不是蝦扯蛋嗎?.....

也許,這樣理解OAuth原理更容易

為什麼不可行

為了實現用戶信息互通而達到業務要求,其實方案有很多。如果不是底線情況下,同步用戶信息這種方案就是一個外行人,一個扯淡的方案。為什麼這麼說?

首先說信息同步這種方式,如果是單項同步,雙方所有相關人員的工作量已經非常之大,一定條件下單項同步升級為雙向信息同步,雙方的編程人員將會苦不堪言。

另外撇開工作量,用戶的信息本質上屬於用戶的私密信息,一個用戶能夠把自己的隱私放心的存儲在你這裡,就說明了對公司的信任度。

一旦發生用戶信息複製的操作,本質上是對用戶的不負責任,道德上,法律上都有所欠缺。

解決方案

作為一個技術人員,排除不合理方案,提供在業務可行情況下的技術方案是職責所在,那有沒有不用複製用戶信息這麼 low B 的方案呢?

假設我們所在公司的系統為 A,業務的域名為 www.A.com,第三方系統為 B,業務域名為 www.B.com。

記住我們的最終業務目標:允許我們公司的用戶(A 系統)在第三方系統(B 系統)能夠登錄,並且能夠獲取用戶一些相關的信息。極限業務情況下,在 A 系統用戶修改了相關信息,並且同步到 B 系統。

解決方案 1

在第三方系統登錄的入口,允許我方用戶輸入賬號密碼,然後第三方系統(客戶端或者服務端都可以)攜帶用戶輸入的賬號密碼請求我司登錄服務器。

如果驗證通過則返回用戶相關信息,第三方系統接收到返回數據,按照自己相關的登錄流程進行登錄,並且可以存儲用戶相關的信息。

請求的形式和大體的流程如下圖所示:

http://www.A.com/login?loginname=caicai&pwd=buzhidao 
也許,這樣理解OAuth原理更容易

說實話,我並不推薦這種方案,雖然它比直接複製用戶信息要好一些,但是依然問題很大,用戶在無形中已經把賬號密碼或者其他登錄憑證洩露給並不信任的第三方系統中,而這可能並非用戶想要的結果。

解決方案 2

以上方案有一個致命的缺點,那就是登錄頁面是用戶並不信任的第三方頁面,如果能避免這樣的危險,讓用戶在信任的我方登錄,會大大增強用戶的信任度。

技術方面在我方實現登錄實在是容易,唯一需要考慮的是用戶登錄成功之後如何把用戶信息發送給第三方系統。

如果採用請求調用的方式(比如:登錄成功,我方調用第三方一個接口),技術上可以實現。

但是下次再來一個第三方申請這樣的業務,我方的調用接口可能會需要修改,所以現在業界比較好的也比較通用的方式是通過地址的跳轉來實現。

具體流程如下:

  • 用戶在第三方點擊登錄,跳轉到我方提供的登錄頁面,頁面 URL 中帶有登錄成功跳轉的頁面地址,並在此頁面輸入賬號密碼。
  • 我方根據用戶賬號密碼判斷用戶正確性,登陸成功,獲取用戶信息。
  • 然後跳轉到第三方提供的登錄成功跳轉頁面,並把用戶信息攜帶過去。
  • 第三方跳轉頁面接收到用戶信息,處理剩餘業務,流程結束。

第一步中第三方跳轉到我方的登錄頁面 URL 如下所示:

http://www.A.com/login?type=userinfo&redirecturi=http://www.B.com/callback 
也許,這樣理解OAuth原理更容易

解決方案 3

方案 2 中登錄部分已經和方案 1 有了本質的區別,雖然僅僅是一個登錄方的改變,安全性以及對用戶隱私的保護上卻有著大大的提升。

但是流程中卻依然存在著主動傳輸用戶信息,如果有人劫持的話,還是有用戶信息洩露的風險。如何避免這樣的風險呢?

試想,能否利用其他憑據來代替用戶信息呢?當然是可以,這也是現代 Web 系統實現授權的普遍方式。

用戶信息取而代之的是一個令牌,而且這個令牌有一定的時效性,只能維持一段時間內有效,這在一定程度上保護了系統數據。

第三方系統獲取到這個令牌之後,每次獲取用戶信息都會攜帶著這個令牌作為憑證,我方的系統同時也只認可這個令牌作為授權的憑證。

http://www.A.com/login?type=token&redirecturi=http://www.B.com/callback 
也許,這樣理解OAuth原理更容易

這裡我要順便說一下,令牌的下發是通過前端(瀏覽器)的跳轉傳輸給第三方系統,然後第三方系統的前端傳輸給後端,然後第三方的後端攜帶令牌獲取用戶信息。

要注意哦,如果是第三方前端頁面攜帶令牌去獲取用戶信息,毫無安全性而言。

解決方案 4

方案 3 其實在很多時候已經足夠了,但是有一點需要注意,每個令牌有一定的有效時間,這是設計上的優勢,同時也意味著令牌如果被其他人獲取到,一樣可以竊取用戶信息。

由於在方案 3 中令牌的下發實際上還是通過前端(瀏覽器)來傳輸的,凡是在前端傳輸的情況下,就會有洩露的風險,那有沒有辦法避免在前端傳輸呢?

這裡需要提醒一點,要想實現我方用戶可以登錄第三方系統,並且在保護用戶隱私的情況下,在我方登錄是必須的。

而且我方系統必須頒發給第三方系統一個憑證才能達到第三方獲取我方用戶的要求。

既然傳輸憑證不可避免,於是人們便想到了可以在前端(瀏覽器)傳輸一個只有一次有效的憑證,然後第三方後端依據這個憑證去獲取令牌,因為服務端的通信要比前端(瀏覽器)的通信要安全的多。

於是方案 4 應運而生:

  • 用戶跳轉到我方登錄頁面進行登錄。
  • 我方驗證用戶用戶名密碼無誤,產生一個有效次數為 1 並且一定時間內有效的 Code,並攜帶著這個 Code 跳轉到第三方的回調頁面。
  • 第三方回調頁面,收到 Code 參數,傳輸給後端程序。
  • 第三方後端程序收到 Code 參數,攜帶著 Code 調用我方接口。
  • 我方驗證 Code 有效性,如果有效則返回令牌信息。
  • 第三方收到令牌信息,攜帶令牌信息調用我方接口獲取用戶信息。
  • 我方驗證 Token 有效性,如果有效則返回用戶信息。
  • 之後的每次調用都攜帶著 Token 進行訪問,Code 就算被人獲取到已經不起作用。
http://www.A.com/login?type=code&redirecturi=http://www.B.com/callback 
也許,這樣理解OAuth原理更容易

升級方案

方案 4 雖然看上去已經足夠好,但是並非完美。主要表現在如下幾點:

①當第三方跳轉到我方登錄頁面的時候,我方並不知道這個第三方是誰,是不是可信任的,所以有必要讓我方識別這個第三方是否可以信任。

我方在授權第三方的時候可以給每一個第三方頒發一個類似於 appid 和 appkey 的數據,appid 用來標識每一個我方授權的第三方,而且每一個 appid 必須註冊進行回調的 URL。

這樣當第三方跳轉到我方登錄頁面的時候,我方就可以識別出來這個第三方以及回調跳轉的 URL 是否有效。

②當第三方攜帶著 Code 去換取 Token,以及之後攜帶 Token 去獲取用戶信息的每次通信,都應該按照我方規則利用 appid 和 appkey 進行簽名處理,這樣我方的服務器端也能夠識別出來調用方是否是可信任的。

③在用戶登錄授權的頁面,用戶可勾選自己授權給第三方的數據內容,這些權限將作用於 Code 以及令牌中。

④由於每個令牌都有失效時間,如何更新令牌則會是一個技術點,其實完全可以在下發令牌的同時也下發一個用於更新令牌的令牌,這個令牌隨著每次重新下發令牌而更新。

⑤我方用戶的信息每次更新的時候,可以把相關的令牌失效,以達到讓第三方重新獲取用戶信息而同步的效果。

⑥我方登錄頁面以及供第三方調用的所有接口都應該採用 HTTPS 協議,並要求所有的第三方回調頁面必須也全部採用 HTTPS,這能有效的防止惡性劫持。

不知道我把不清楚 author2.0 授權的同學教會了沒有,如果還不清楚,請底部留言交流。


分享到:


相關文章: