深度解析OAuth 2.0授權!!

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以下業務場景只針對於Web系統,而且Web頁面有後臺服務程序的場景。"}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"#開端","title":null}},{"type":"text","text":"開端"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那一年,我所在公司的用戶量達到了公司成立以來的新高峯,經過多個程序員日日夜夜加班,每個業務系統達到了幾乎四個9的穩定性,同時業務在業界也有了一定的知名度。那一天突然有一個合作商登門拜訪,提出合作共贏的意向。業務的場景就是我們的系統用戶能夠在他們系統登錄,並能夠獲取用戶一定的信息以便進行一些業務操作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"他們希望我們能夠把已存在的用戶數據Copy一份導入他們的系統,並且新註冊的用戶進行單項同步更新。這不是蝦扯蛋嗎?....."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/15/15305a234b9897cf2cf62bd6fe1a420a.jpeg","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"#爲什麼不可行","title":null}},{"type":"text","text":"爲什麼不可行"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了實現用戶信息互通而達到業務要求,其實方案有很多。如果不是底線情況下,同步用戶信息這種方案就是一個外行人,一個扯淡的方案。爲什麼這麼說?首先說信息同步這種方式,如果是單項同步,雙方所有相關人員的工作量已經非常之大,一定條件下單項同步升級爲雙向信息同步,雙方的編程人員將會苦不堪言。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外撇開工作量,用戶的信息本質上屬於用戶的私密信息,一個用戶能夠把自己的隱私放心的存儲在你這裏,就說明了對公司的信任度。一旦發生用戶信息複製的操作,本質上是對用戶的不負責任,道德上,法律上都有所欠缺。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"#解決方案","title":null}},{"type":"text","text":"解決方案"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作爲一個技術人員,排除不合理方案,提供在業務可行情況下的技術方案是職責所在,那有沒有不用複製用戶信息這麼low B的方案呢?假設我們所在公司的系統爲A,"},{"type":"link","attrs":{"href":"http://xn--www-o48dufl4y2ucszljt8e.A.com","title":null},"content":[{"type":"text","text":"業務的域名爲www.A.com"}]},{"type":"text","text":",第三方系統爲B,"},{"type":"link","attrs":{"href":"http://xn--www-o48dufl4y2ucszl.B.com","title":null},"content":[{"type":"text","text":"業務域名爲www.B.com"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"記住我們的最終業務目標:允許我們公司的用戶(A系統)在第三方系統(B系統)能夠登錄,並且能夠獲取用戶一些相關的信息。極限業務情況下,在A系統用戶修改了相關信息,並且同步到B系統。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#解決方案1","title":null}},{"type":"text","text":"解決方案1"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在第三方系統登錄的入口,允許我方用戶輸入賬號密碼,然後第三方系統(客戶端或者服務端都可以)攜帶用戶輸入的賬號密碼請求我司登錄服務器,如果驗證通過則返回用戶相關信息,第三方系統接收到返回數據,按照自己相關的登錄流程進行登錄,並且可以存儲用戶相關的信息。請求的形式和大體的流程如下圖所示"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"http://www.A.com/login?loginname=caicai&pwd=buzhidao\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/27/273b1982f72fff175f7442592f40d215.jpeg","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"說實話,我並不推薦這種方案,雖然它比直接複製用戶信息要好一些,但是依然問題很大,用戶在無形中已經把賬號密碼或者其他登錄憑證泄露給並不信任的第三方系統中,而這可能並非用戶想要的結果。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#解決方案2","title":null}},{"type":"text","text":"解決方案2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以上方案有一個致命的缺點,那就是登錄頁面是用戶並不信任的第三方頁面,如果能避免這樣的危險,讓用戶在信任的我方登錄,會大大增強用戶的信任度。技術方面在我方實現登錄實在是容易,唯一需要考慮的是用戶登錄成功之後如何把用戶信息發送給第三方系統。如果採用請求調用的方式(比如:登錄成功,我方調用第三方一個接口),技術上可以實現,但是下次再來一個第三方申請這樣的業務,我方的調用接口可能會需要修改,所以現在業界比較好的也比較通用的方式是通過地址的跳轉來實現。具體流程如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"用戶在第三方點擊登錄,跳轉到我方提供的登錄頁面,頁面URL中帶有登錄成功跳轉的頁面地址,並在此頁面輸入賬號密碼。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"我方根據用戶賬號密碼判斷用戶正確性,登陸成功,獲取用戶信息。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"然後跳轉到第三方提供的登錄成功跳轉頁面,並把用戶信息攜帶過去。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"第三方跳轉頁面接收到用戶信息,處理剩餘業務,流程結束。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一步中第三方跳轉到我方的登錄頁面URL如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"http://www.A.com/login?type=userinfo&redirecturi=http://www.B.com/callback\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/62/629e3b2196c704c72a9ca4e8faf539c2.jpeg","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#解決方案3","title":null}},{"type":"text","text":"解決方案3"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"方案2中登錄部分已經和方案1有了本質的區別,雖然僅僅是一個登錄方的改變,安全性以及對用戶隱私的保護上卻有着大大的提升。但是流程中卻依然存在着主動傳輸用戶信息,如果有人劫持的話,還是有用戶信息泄露的風險。如何避免這樣的風險呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"試想,能否利用其它憑據來代替用戶信息呢?當然是可以,這也是現代Web系統實現授權的普遍方式。用戶信息取而代之的是一個令牌,而且這個令牌有一定的時效性,只能維持一段時間內有效,這在一定程度上保護了系統數據。第三方系統獲取到這個令牌之後,每次獲取用戶信息都會攜帶者這個令牌作爲憑證,我方的系統同時也只認可這個令牌作爲授權的憑證。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"http://www.A.com/login?type=token&redirecturi=http://www.B.com/callback\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a2/a2266404404ff8b2cb05555b4e27fd45.jpeg","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我要順便說一下,令牌的下發是通過前端(瀏覽器)的跳轉傳輸給第三方系統,然後第三方系統的前端傳輸給後端,然後第三方的後端攜帶令牌獲取用戶信息,要注意哦,如果是第三方前端頁面攜帶令牌去獲取用戶信息,毫無安全性而言。"}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#方案4","title":null}},{"type":"text","text":"方案4"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"方案3其實在很多時候已經足夠了,但是有一點需要注意,每個令牌有一定的有效時間,這是設計上的優勢,同時也意味着令牌如果被其他人獲取到,一樣可以竊取用戶信息,由於在方案3中令牌的下發實際上還是通過前端(瀏覽器)來傳輸的,凡是在前端傳輸的情況下,就會有泄露的風險,那有沒有辦法避免在前端傳輸呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏需要提醒一點,要想實現我方用戶可以登錄第三方系統,並且在保護用戶隱私的情況下,在我方登錄是必須的。而且我方系統必須頒發給第三方系統一個憑證才能達到第三方獲取我方用戶的要求。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"既然傳輸憑證不可避免,於是人們便想到了可以在前端(瀏覽器)傳輸一個只有一次有效的憑證,然後第三方後端依據這個憑證去獲取令牌,因爲服務端的通信要比前端(瀏覽器)的通信要安全的多。於是方案4應運而生:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"用戶跳轉到我方登錄頁面進行登錄。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"我方驗證用戶用戶名密碼無誤,產生一個有效次數爲1並且一定時間內有效的code,並攜帶着這個code跳轉到第三方的回調頁面"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"第三方回調頁面,收到code參數,傳輸給後端程序。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"第三方後端程序收到code參數,攜帶着code調用我方接口"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"我方驗證code有效性,如果有效則返回令牌信息"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"text","text":"第三方收到令牌信息,攜帶令牌信息調用我方接口獲取用戶信息"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":7,"align":null,"origin":null},"content":[{"type":"text","text":"我方驗證token有效性,如果有效則返回用戶信息"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":8,"align":null,"origin":null},"content":[{"type":"text","text":"之後的每次調用都攜帶者token進行訪問,code就算被人獲取到已經不起作用"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"http://www.A.com/login?type=code&redirecturi=http://www.B.com/callback\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/94/9491a80ee8536d97154c98f1a6e255d2.jpeg","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#升級","title":null}},{"type":"text","text":"升級"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"方案4雖然看上去已經足夠好,但是並非完美。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"當第三方跳轉到我方登錄頁面的時候,我方並不知道這個第三方是誰,是不是可信任的,所以有必要讓我方識別這個第三方是否可以信任。我方在授權第三方的時候可以給每一個第三方頒發一個類似於appid和appkey的數據,appid用來標識每一個我方授權的第三方,而且每一個appid必須註冊進行回調的url。這樣當第三方跳轉到我方登錄頁面的時候,我方就可以識別出來這個第三方以及回調跳轉的url是否有效。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"當第三方攜帶者code去換取token,以及之後攜帶token去獲取用戶信息的每次通信,都應該按照我方規則利用appid和appkey進行簽名處理,這樣我方的服務器端也能夠識別出來調用方是否是可信任的。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"在用戶登錄授權的頁面,用戶可勾選自己授權給第三方的數據內容,這些權限將作用於code以及令牌中。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"由於每個令牌都有失效時間,如何更新令牌則會是一個技術點,其實完全可以在下發令牌的同時也下發一個用於更新令牌的令牌,這個令牌隨着每次重新下發令牌而更新。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"我方用戶的信息每次更新的時候,可以把相關的令牌失效,以達到讓第三方重新獲取用戶信息而同步的效果"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"text","text":"我方登錄頁面以及供第三方調用的所有接口都應該採用https協議,並要求所有的第三方回調頁面必須也全部採用https,這能有效的仿製惡性劫持。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不知道菜菜把不清楚OAuth2.0 授權的同學教會了沒有,如果還不清楚,請私信菜菜"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"更多精彩文章"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342955119549267969&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"分佈式大併發系列"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342959003139227648&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"架構設計系列"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342962375443529728&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"趣學算法和數據結構系列"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342964237798391808&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"設計模式系列"}]}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f8/f8af5984765a267892bf1a1272272625.png","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章