OAuth 2.0 與 OIDC

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"OAuth","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什麼是 OAuth?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"高層次來說,OAuth 不是一個 API 或者服務:它是一個授權開放標準,並且任何人都可以實現它。","attrs":{}}]},{"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":"更明確來說,OAuth 是一個標準,應用程序可以用來提供客戶端程序“安全授權訪問”。OAuth 在 HTTPs 上工作並通過訪問令牌授權設備、API、服務、和應用程序,而不是憑證。","attrs":{}}]},{"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":"有兩個版本的 OAuth:OAuth 1.0a 和 OAuth 2.0 。這些規範是完全不同的,並且不能一起使用,它們之間沒有向後兼容。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"爲什麼是 OAuth?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OAuth 的創建,是對直接認證模式的迴應。這個模式因 HTTP Basic 認證而聞名,提示用戶輸入用戶名和密碼。Basic 認證一直用於服務器端應用程序 API 認證的原始表單:替代每次請求發送用戶名和密碼,用戶發送一個 API key ID 和密鑰。在 OAuth 之前,網站提示你鍵入用戶名和密碼到一個表單中,它們會以你的身份登錄到你的數據中(例如:你的 Gmail 賬戶)。通常這叫做密碼反模式。","attrs":{}}]},{"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 系統,聯合身份被創建用於單點登錄(SSO)。在這種場景下,終端用戶和他們的身份提供商對話,並且身份提供商生成一個加密的簽名令交給應用程認證用戶。應用程序信任身份提供商。只要信任關係和簽名斷言工作,就沒問題。下圖顯示如何工作。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/52/526ec5e2e3ffdf9cd83f79e090b61208.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"聯合身份因 SAML 2.0(一個發佈於 2005/03/15 的 OASIS 標準) 出名。它是一個巨大的規範,但是主要的兩個組件是它的認證請求協議(也叫做 Web SSO)和它打包身份特性並對其簽名的方式,被叫做 SAML 斷言。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"SAML","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SAML 在你的瀏覽器中是一個基礎的會話緩存讓你訪問 Web 應用程序。它受限於設備文件類型和瀏覽器之外的場景。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"OAuth 和 API","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們構建 API 的方式也發生了很大的變化。在 2015 年,大家投入 WS-* 構建 Web 服務。如今,大多數開發者已經遷移到 REST 和無狀態 API。REST 簡單的說是 HTTP 命令通過網絡推送 JSON 包。","attrs":{}}]},{"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":"開發者構建大量的 API。如今 API 經濟可能是你在會議室中常聽見的詞彙。公司需要保護他們的 REST API,以一種允許很多設備訪問它們的方式。在從前,你要輸入你的用戶名、密碼目錄,然後 app 以你的身份登錄。這就產生了授權問題。","attrs":{}}]},{"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":"“我如何允許一個 app 訪問我的數據而不需要給它我的密碼?”","attrs":{}}]},{"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":"如果你見過下面的會話,那就是我們在談論的。一個應用程序請求它是否可以代表你訪問數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/dd/dd0eded81e8af7bea0fb0b6ba5252587.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"這就是 OAuth。","attrs":{}}]},{"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":"OAuth 是一個用於 REST/API 委託授權框架。它使應用程序能夠在不泄露用戶密碼的情況下獲得用戶數據的有限訪問(scopes)。它從授權中解綁認證並支持多用戶實例定位到不同設備的能力。它支持服務到服務的應用程序、以瀏覽器爲基礎的應用程序、移動端/原生 app、控制檯程序和電視應用程序。","attrs":{}}]},{"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":"你可以認爲這就像旅館的房卡,但是用於應用程序。如果你有一個旅館的房卡,你可以進入你的房間。你如果獲取一個旅館的房卡?你必須在前臺做一個認證流程以得到房卡。認證後獲得房卡,你可以通過旅館訪問資源。","attrs":{}}]},{"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":"簡單的分解後, OAuth 是:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"App 從用戶請求授權","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"用戶授權 App 並且傳遞驗證","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"App 提交授權驗證到服務器獲取一個令牌","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"令牌被限制只能訪問用戶爲特定應用授權的內容","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"OAuth 主要組件","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OAuth 構建於下列主要組件之上:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作用域和准許(Scopes and Consent)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"參與者(Actors)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"客戶端(Clients)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"令牌(Tokens)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"授權服務(Authorization Server)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"工作流(Flows)","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"OAuth 作用域","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作用域是當應用程序請求許可時你在授權頁面上看到的內容。它們是客戶端在請求令牌時請求的權限包(權限包:一堆權限)。它們是程序員在寫應用程序時寫的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/44/44379144d63bdc6678141fad78671656.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"作用域從強制中解耦授權策略決策。這是 OAuth 的第一個關鍵點。權限是最重要的。它們不隱藏在需要你逆向工程的應用程序層後面。它們通常在 API 文檔中列出:這些作用域是這個應用程序需要的。","attrs":{}}]},{"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 上是十分重要的用戶體驗變更。大多數人在 OAuth 之前僅使用用戶名和密碼會話框。現在你有提出新的頁面,你必須培訓用戶使用它。重新培訓網民是困難的。有各種各樣的用戶,從精通科技的年輕人到不熟悉這一流程的祖父母。它在 Web 上是一個新的概念,如今很重要。現在你需要授權和准許。","attrs":{}}]},{"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":"准許在應用程序的基礎上是可以變化的。它可以是時間敏感的時間範圍(天,周,月),但並不是所有平臺都允許你選擇持續時間。需要注意的是,當你准許時,應用程序可以代表你做事情,例如:LinkedIn 向你的社交網絡中的每個人發送垃圾郵件。","attrs":{}}]},{"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":"OAuth 是互聯網規模的解決方案,因爲它針對每一個應用程序。通常你有能力登錄到一個儀表盤以查看你給什麼應用程序准許訪問以及取消准許。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"OAuth 參與者","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OAuth 工作流參與者如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"資源擁有者:在資源服務器上擁有數據。例如:我是我的 Facebook 個人文檔的資源擁有者。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"資源服務器:應用程序要訪問的保存數據的 API","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"客戶端:要訪問你數據的應用程序","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"授權服務器:OAuth 引擎","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/35/35291179618b8ae47e2d8c83816c4df1.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"資源擁有者是一個可以變更不同憑證的角色。它可以是一個終端用戶,也可以是一家公司。","attrs":{}}]},{"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":"客戶端可以是公開的和保密的。兩者間有一個明顯的區別在 OAuth 命名規則中。保密的客戶端可以通過保存祕密以被信任。保密的客戶端不是在桌面運行或者通過應用商店分發。人們不能逆向工程它們以獲取密鑰。它們在一個受保護的區域(終端用戶不能訪問它們)運行。","attrs":{}}]},{"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":"公共客戶端是瀏覽器、手機 app、和物聯網設備。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8a/8a92a5703786999be50c74c041b48bcc.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"客戶端註冊也是 OAuth 的關鍵組件。它像 OAuth 的車管所。你需要爲你的應用程序獲取車牌號。這就是你的應用程序如何在授權會話顯示 Logo。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"OAuth 令牌","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"訪問令牌是客戶端用於訪問資源服務器(API)的令牌。它們意味着是暫時的。用小時和分鐘來考慮它們,而不是天和月。你不需要一個機密的客戶端以獲取訪問令牌。你可以通過公共客戶端獲取訪問令牌。它們被設計爲優化互聯網規模問題。因爲這些令牌是短暫和可向外擴展的,它們不能被取消,你只需要等待它們過期。","attrs":{}}]},{"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":"另一個令牌是刷新令牌。這有效期是比較長的(天、月、年)。它用於獲取新的令牌。要獲取刷新令牌,應用程序通常需要具有認證的機密客戶端。","attrs":{}}]},{"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":"刷新令牌可以被取消。當在儀表盤中取消一個應用程序的訪問時,你殺掉了它的刷新令牌。這給了你強制客戶端輪換祕密的能力。你要做的是,使用你的刷新令牌去獲取新的訪問令牌,訪問令牌通過網絡命中訪問所有 API 資源。每一次你刷新你的訪問令牌你將獲取一個新的加密簽名令牌。系統中內置了輪換按鈕。","attrs":{}}]},{"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":"OAuth 規範沒有定義令牌是什麼樣子。它可以是任何你想要的格式。但通常是這樣,你要這些令牌是一個 JWT(JSON Web Tokens)。簡而言之,JWT 是一個安全和值得信任的令牌驗證標準。JWT 允許你使用簽名對信息(稱爲聲明)進行數字簽名,並且可以在以後使用祕密簽名密鑰進行驗證。","attrs":{}}]},{"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":"令牌從授權服務器上的端點上取回。兩個主要的端點是授權端點和令牌端點。它們針對不同的用例進行了分隔。授權端點是你要從用戶那獲得准許和授權的地方。返回一個用戶已經准許的授權許可。然後授權傳遞到令牌端點。令牌端點處理許可並且說“好極了,這是你的刷新令牌和你的訪問令牌”。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5d/5dcee068f1a831e452f58a16e5cc5238.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"你可以使用訪問令牌訪問 API。一旦令牌過期,你必須帶着刷新令牌返回令牌端點以獲取新的訪問令牌。","attrs":{}}]},{"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":"缺點是這會引起很多開發者的摩擦。OAuth 最大的痛點是開發者必須管理刷新令牌。你把狀態管理推到每個客戶端開發者的身上。你得到刷新按鈕的好處,但是你製造了開發者的痛點。那就是爲什麼開發者喜愛 API 密鑰的原因。他們只需要拷貝、粘貼密鑰,把它們放在一個文本里,然後就完成了。API 密鑰對於開發者來說非常方便,但是對於安全性來說非常糟糕。","attrs":{}}]},{"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":"這裏有一個付費遊戲的問題。讓開發者做 OAuth 流提高安全性,但會產生更多的摩擦。對於工具箱和平臺來說是有機會簡化事情並幫助管理令牌。幸好,OAuth 現在已經相當成熟了,你最喜歡的語言或框架可能有工具可以簡化事情。","attrs":{}}]},{"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":"我們已經略微聊了關於客戶端類型、令牌類型、授權服務器端點和我們如何把它們傳遞到資源服務器。我提到兩個不同的流:獲取授權和獲取令牌。這些不需要在同一個渠道上產生。前端渠道通過瀏覽器。瀏覽器重定向用戶到授權服務器,用戶給予准許。這在用戶的瀏覽器上產生。一旦用戶獲得授權許可並交給應用程序,客戶端應用程序就不再需要使用瀏覽器完成 OAuth 流獲取令牌了。","attrs":{}}]},{"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":"令牌將被客戶端應用程序使用,以便它能夠代表你訪問資源。我們叫做後端渠道。後端渠道是一個直接從客戶端應用程序發起,到資源服務器的 HTTP 調用,以交換授權許可獲得令牌。這些渠道用於不同的流取決於你有什麼樣的設備能力。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2a/2a0afeedad51550636ac27ed5ad26489.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"例如,一個前端渠道流通過用戶代理授權看起來是這樣的:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"資源擁有人啓動流,委託訪問,保護資源","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"客戶端帶着需要的作用域通過瀏覽器發送授權請求重定向到授權服務器上的授權端點","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"授權服務器返回一個准許會話,說“你是否允許這個應用程序訪問這些作用域?”,當然你需要認證應用程序,假如你沒有認證你的資源服務器,它會要求你登錄。如果你已經緩存了會話緩存,你只會看到準可會話框。查看準可會話,然後同意。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"授權許可通過瀏覽器重定向回傳到應用程序。這就是前端渠道發生的所有事情。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/73/73fae2d9fcb5e8bbb908c51e9526719e.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"在這個流程中還有一個變量叫做隱式流程。我們馬上就會講到。","attrs":{}}]},{"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":"這是在網絡中看到的。","attrs":{}}]},{"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":"Request","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"curl"},"content":[{"type":"text","text":"GET https://accounts.google.com/o/oauth2/auth?scope=gmail.insert gmail.send\n&redirect_uri=https://app.example.com/oauth2/callback\n&response_type=code&client_id=812741506391\n&state=af0ifjsldkj\n","attrs":{}}]},{"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":"這是一個帶着一堆查詢參數的 GET 請求(不是以 URL 編碼爲目的的示例)。作用域(Scopes)來自 Gmail 的 API。redirect_uri 是客戶端應用程序的 URL,授權許可應該返回到該 URL。這應該匹配來自客戶端註冊過程的值(在車管所)。你不希望授權退回到外部應用程序。響應類型改變 OAuth 流。客戶端 ID 也來自注冊流程。狀態是一個安全標記,類似 XRSF。","attrs":{}}]},{"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":"Response","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"curl"},"content":[{"type":"text","text":"HTTP/1.1 302 Found\nLocation: https://app.example.com/oauth2/callback?\ncode=MsCeLvIaQm6bTrgtp7&state=af0ifjsldkj\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"code","attrs":{}}],"attrs":{}},{"type":"text","text":" 返回的是授權許可,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"state","attrs":{}}],"attrs":{}},{"type":"text","text":"確保非僞造並且來自同一個請求。","attrs":{}}]},{"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":"前端渠道完成後,一個後端渠道流產生了,交換授權碼得到訪問令牌。","attrs":{}}]},{"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":"客戶端應用程序發送一個訪問令牌請求(帶着機密客戶端證書和客戶端 ID)到授權服務器上的令牌端點。這個過程交換一個授權碼許可得到一個訪問令牌和(可選)一個刷新令牌。客戶端通過訪問令牌訪問受保護的資源。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/95/9574f3de905a838d4011754f3e88469d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"以下是原始 HTTP 看到的樣子。","attrs":{}}]},{"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":"Request","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"curl"},"content":[{"type":"text","text":"POST /oauth2/v3/token HTTP/1.1\nHost: www.googleapis.com\nContent-Type: application/x-www-form-urlencoded\n\ncode=MsCeLvIaQm6bTrgtp7&client_id=812741506391&client_secret={client_secret}&redirect_uri=https://app.example.com/oauth2/callback&grant_type=authorization_code\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"grant_type","attrs":{}}],"attrs":{}},{"type":"text","text":" 是 OAuth 的擴展部分。從預先計算的角度來看,它是一個授權碼。它帶來了靈活性,可以用不同的方式描述這些授權。這在 OAuth 流中是最常見的類型。","attrs":{}}]},{"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":"Response","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"curl"},"content":[{"type":"text","text":"{\n \"access_token\": \"2YotnFZFEjr1zCsicMWpAA\",\n \"token_type\": \"Bearer\",\n \"expires_in\": 3600,\n \"refresh_token\": \"tGzv3JOkF0XG5Qx2TlKWIA\"\n}\n","attrs":{}}]},{"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":"響應是 JSON。在使用令牌時,你可以時被動或主動的。主動是在你的客戶端中有一個定時器。被動是獲取一個錯誤然後嘗試重新獲取一個新的令牌。","attrs":{}}]},{"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":"一旦你有了訪問令牌,你可以在認證頭(使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"token_type","attrs":{}}],"attrs":{}},{"type":"text","text":"做爲前綴)中使用反問令牌發起對受保護資源的訪問。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"curl"},"content":[{"type":"text","text":"curl -H \"Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA\" \\\n https://www.googleapis.com/gmail/v1/users/1444587525/messages\n","attrs":{}}]},{"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":"目前你有一個前端渠道,一個後端渠道、不同的端點和不同的客戶端。你必須爲不同的用例混合和匹配這些。這提高了 OAuth 的複雜性,可能會讓人感到困惑。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"OAuth 工作流","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隱式流(Implicit Flow)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"授權碼流(Authorization Code Flow)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"客戶端憑證流(Client Credential Flow)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"資源擁有者密碼流(Resource Owner Password Flow)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"斷言流(Assertion Flow)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設備流(Device Flow)","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"OAuth 不是一個認證協議","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"總結 OAuth 2.0 的一些錯誤觀念:它不向後兼容 OAuth 1.0。它將所有通信的簽名替換爲 HTTPS。如今當人們談論 OAuth 時,他們談論的是 OAuth 2.0。","attrs":{}}]},{"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":"因爲 OAuth 是一個授權框架不是一個協議,你可能有互操作性問題。在團隊實現 OAuth 時有很多變量,你可以需要自定義代碼與供應商集成。","attrs":{}}]},{"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":"OAuth 2.0 不是一個認證框架。","attrs":{}}]},{"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":"我們一直在討論委託授權。而不是認證用戶,這是關鍵。OAuth 2.0 單獨來說絕對和用戶沒有一點關係。你只是通過令牌訪問資源。","attrs":{}}]},{"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":"最近幾年 OAuth 產生了有巨量的附屬。它們又在 OAuth 上添加了複雜性以完成各種企業場景。例如:JWT 可用做互操作令牌,可以對其進行簽名和加密。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"通過 OAuth 2.0 僞認證","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過 OAuth 登錄因 FaceBook Connect 和 Twitter 出名。在這個工作流下,客戶端通過訪問令牌訪問 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"/me","attrs":{}}],"attrs":{}},{"type":"text","text":" 端點。它只是說客戶端可以通過令牌訪問資源。人們發明這個假的端點做爲通過令牌獲取用戶信息的一種方式。它不是獲取用戶信息的標準方式。標準中沒有提及要實現這個端點。訪問令牌是不透明的。它們爲 API 而設計的,而不是爲包含用戶信息而設計的。","attrs":{}}]},{"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":"通過身份認證,你要回答的是用戶是誰、用戶何時認證的和用戶如何認證的。通常可以使用 SAML 斷言回答這些問題,而不是訪問令牌和授權許可。這是爲什麼我們把這個叫做僞認證的原因。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"進入 OpenID Connect","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了解決僞認證問題,OAuth 2.0、Facebook Connect和 SAML 2.0 最好的部分聯合創建了 OpenID Connect。OpenID Connect(OIDC)擴展 OAuth 2.0,爲客戶端提供一個新的簽名 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"id_token","attrs":{}}],"attrs":{}},{"type":"text","text":" 和一個 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"UserInfo","attrs":{}}],"attrs":{}},{"type":"text","text":" 端點以拉取用戶特性。不像 SAML,OIDC 提供一個作用域標準集和身份聲明。例如包含:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"profile","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"email","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"address","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"phone","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"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":"OIDC 是通過使事物完全動態來實現互聯網可擴展的。不再需要像 SAML 要求的那樣,下載元數據和聯合。內置了註冊、發現、動態聯合的元數據。你可以鍵入你的郵件地址,然後它動態的發現你的 OIDC 提供商,動態下載元數據,動態知道它要使用什麼證書,並且允許 BYOI(Bring Your Own Identity,帶上你自己的身份)。它支持企業的高保證級別和關鍵 SAML 用例。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ac/ac76a6d122ae4195834a4ec810f57d23.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"OIDC 因 Google 和微軟出名,兩者都是早期使用者。Okta 在 OIDC 中也做了巨大投入。","attrs":{}}]},{"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":"初始請求中所改變是,它包含標準作用域(例如:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"openid","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"email","attrs":{}}],"attrs":{}},{"type":"text","text":"):","attrs":{}}]},{"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":"Request","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"curl"},"content":[{"type":"text","text":"GET https://accounts.google.com/o/oauth2/auth?\nscope=openid email&\nredirect_uri=https://app.example.com/oauth2/callback&\nresponse_type=code&\nclient_id=812741506391&\nstate=af0ifjsldkj\n","attrs":{}}]},{"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":"Response","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"curl"},"content":[{"type":"text","text":"HTTP/1.1 302 Found\nLocation: https://app.example.com/oauth2/callback?\ncode=MsCeLvIaQm6bTrgtp7&state=af0ifjsldkj\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"code","attrs":{}}],"attrs":{}},{"type":"text","text":" 返回的是授權許可,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"state","attrs":{}}],"attrs":{}},{"type":"text","text":" 確保不被僞造並且來自同一個請求。","attrs":{}}]},{"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":"並且授權許可響應令牌包含一個 ID Token。","attrs":{}}]},{"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":"Request","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"curl"},"content":[{"type":"text","text":"POST /oauth2/v3/token HTTP/1.1\nHost: www.googleapis.com\nContent-Type: application/x-www-form-urlencoded\n\ncode=MsCeLvIaQm6bTrgtp7&client_id=812741506391&\n client_secret={client_secret}&\n redirect_uri=https://app.example.com/oauth2/callback&\n grant_type=authorization_code\n","attrs":{}}]},{"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":"Response","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"curl"},"content":[{"type":"text","text":"{\n \"access_token\": \"2YotnFZFEjr1zCsicMWpAA\",\n \"token_type\": \"Bearer\",\n \"expires_in\": 3600,\n \"refresh_token\": \"tGzv3JOkF0XG5Qx2TlKWIA\",\n \"id_token\": \"eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ...\"\n}\n","attrs":{}}]},{"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":"看得出這是在 OAuth 上很好的分層,返回一個 ID Token 做爲結構化令牌。ID Token 是一個 JWT。JWT 比一個巨大的以 XML 爲基礎的 SAML 斷言要小的多,並且可以極具效率的在不同的設備間傳遞。一個 JWT 包含三個部分:消息頭、消息體和簽名。消息頭表明用什麼算法對其進行簽名,Claims(聲明) 在消息體中,簽名內容保存在簽名中。","attrs":{}}]},{"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":"OIDC 工作流包含以下幾個步驟:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"發現 OIDC 元數據","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"執行 OAuth 工作流獲取 ID Token 和訪問令牌","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"獲取 JWT 密鑰然後(可選)動態註冊客戶端程序","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"本地驗證 JWT ID Token,以內置日期和簽名爲基礎","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"根據需要通過訪問令牌獲取用戶其它特性","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/aa/aa77bf659dfd12fbb54c8b4f3c9bc2e4.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"OAuth 2.0 總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OAuth 2.0 是一個用於授權訪問 API 的授權框架。它包含資源擁有者授權或者給予准許客戶端請求作用域。授權許可用於交換訪問令牌和刷新令牌(取決於工作流)。有多個工作流適用不同的客戶端和授權場景。 JWT 可以用於結構化令牌,在授權服務器和資源服務器之間。","attrs":{}}]},{"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":"OAuth 有一個很大的安全的表面。確保使用安全的工具箱驗證所有輸入。","attrs":{}}]},{"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":"OAuth 不是一個認證協議。OIDC 擴展 OAuth 2.0 以適應驗證場景。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"OAuth 2.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OAuth 2.0 是工業級標準授權協議。 OAuth 2.0 聚焦於客戶端開發者便利性,爲網頁應用程序、桌面客戶端、手機、客廳設備提供特定的授權流程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.rfc-editor.org/info/rfc6749","title":"","type":null},"content":[{"type":"text","text":"RFC6749","attrs":{}}]},{"type":"text","text":" OAuth 2.0 授權框架","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.rfc-editor.org/info/rfc6750","title":"","type":null},"content":[{"type":"text","text":"RFC6750","attrs":{}}]},{"type":"text","text":" OAuth 2.0 授權框架:使用 Bearer Token","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://datatracker.ietf.org/doc/draft-ietf-oauth-security-topics/","title":"","type":null},"content":[{"type":"text","text":"OAutho 2.0 安全當前最佳實踐","attrs":{}}]},{"type":"text","text":"——注意,此文檔僅是草稿,很有可能隨時會被替換或者被棄用。在這裏引用的目的是爲了提升對 OAuth 2.0 的理解和當前應用場景下 OAuth 2.0 存在的一些問題。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"PKCE","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.rfc-editor.org/info/rfc7636","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"RFC7636","attrs":{}}]},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":":Proof Key for Code Exchange","attrs":{}}]},{"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":"PKCE 是授權碼流(Authorization Code Flow)的一個擴展,以阻止幾個攻擊並且能夠安全的在公共客戶端間執行 OAuth 交換。起初它設計用於保護移動端 app,由於它能夠阻止授權碼注入,所以對於任何 OAuth 客戶端來說它都很有用,甚至使用客戶端密鑰的 Web 應用程序。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"權限類型","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Authorization Code","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"授權碼權限類型用於保密,並且公共客戶端通過交換授權碼以獲取訪問令牌。","attrs":{}}]},{"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 返回客戶端後,應用程序將會從 URL 中獲取授權碼並用於獲取一個訪問令牌。","attrs":{}}]},{"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":"在這個流下,推薦所有客戶端都使用 PKCE 擴展以便提供更好的安全性。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"OAuth 2.1","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OAuth 2.1 是一項正在努力中的工作。以鞏固和簡化 OAuth 2.0 中最常用的功能。","attrs":{}}]},{"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":"自從 2012 年發佈初版 OAuth 2.0 (RFC6749)以來,幾個新的徵求意見稿(RFC)也發佈了,要從核心規則中添加或移除功能。包括","attrs":{}},{"type":"link","attrs":{"href":"https://www.rfc-editor.org/info/rfc8252","title":"","type":null},"content":[{"type":"text","text":"雲原生 Apps OAuth 2.0(RFC8252)","attrs":{}}]},{"type":"text","text":"、","attrs":{}},{"type":"link","attrs":{"href":"https://www.rfc-editor.org/info/rfc7636","title":"","type":null},"content":[{"type":"text","text":"PKCE","attrs":{}}]},{"type":"text","text":"、瀏覽器應用授權、OAutho 2.0 安全當前最佳實踐。","attrs":{}}]},{"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":"和 OAuth 2.0 主要的不同如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所有使用授權碼流程的客戶端都需要 ","attrs":{}},{"type":"link","attrs":{"href":"https://www.rfc-editor.org/info/rfc7636","title":"","type":null},"content":[{"type":"text","text":"PKCE","attrs":{}}]},{"type":"text","text":"(Proof Key for Code Exchange)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"必須使用精確字符串匹配來比較重定向 URI","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從 OAuth 2.0 中刪除隱式授權,也叫簡單模式(response_type=token)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從 OAuth 2.0 中移除密碼模式","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Bearer 令牌使用,移除在 URI 中 query 字符串中使用 Bearer 令牌","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"公共客戶端刷新令牌必須受發送端限制或是一次性的","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"基於 OAuth 2.0 構建的協議","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://openid.net/connect/","title":"","type":null},"content":[{"type":"text","text":"OpenID Connect(OpenID Foundation)","attrs":{}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-grant-2.0.html","title":"","type":null},"content":[{"type":"text","text":"UMA 2.0(Kantara)","attrs":{}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://indieauth.spec.indieweb.org/","title":"","type":null},"content":[{"type":"text","text":"IndieAuth(W3C)","attrs":{}}]}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"OpenID Connect","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"什麼是 OpenID Connect?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OpenID Connect 1.0 是在 OAuth 2.0 協議上的身份層。它允許客戶端基於認證服務器執行認證以驗證終端用戶的身份,同時以一個可互操作和類 REST 的方式獲取終端用戶的基礎信息。","attrs":{}}]},{"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":"OpenID Connect 允許所有的客戶端類型(包含以 Web 爲基礎的、移動端、JavaScript 客戶端)請求和接收關於認證會話和終端用戶的信息。規範套件是可擴展的,允許參與者使用可選功能(比如:身份信息加密、OpenID 提供者發現、會話管理)。當可選功能對參與者有意義時。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"OpenID Connect 如何不同於 OpenID 2.0?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OpenID Connect 如同 OpenID 2.0 一樣執行很多相同的任務,但以 API 友好的方式,並且用於原生和移動端應用程序。OpenID Connect 定義可選機制以實現健壯的簽名和加密。鑑於集成 OAuth 1.0a 和 OpenID 2.0 需要擴展,在 OpenID Connect 中,協議自己集成了 OAuth 2.0 的能力。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"規範組織","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OpenID Connect 1.0 規範由以下文檔組成:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Core —— 定義 OpenID Connect 核心功能:在 OAuth 2.0 上構建認證並且使用 Claims 和終端用戶溝通信息","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Discovery ——(可選)定義客戶端如何動態發現 OpenID 提供者信息","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Dynamic Registration ——(可選)定義客戶端如何動態註冊 OpenID 提供者","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OAuth 2.0 Mutiple Response Types —— 定義幾個具體的 OAuth 2.0 返回類型","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OAuth 2.0 Form Post Response Mode —— (可選)定義如何返回 OAuth 2.0 授權響應參數(包含 OpenID Connect 認證響應參數)使用 HTML 表單值,通過用戶代理使用 HTTP POST 自動提交","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"RP-Initiated Logout ——(可選)定義一個依賴方如何要求 OpenID 提供商從終端用戶退出登錄","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Session Management ——(可選)定義如何管理 OpenID Connect 會話,包括以 postMessage 爲基礎的退出登陸和 RP-initiated 退出登錄功能","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Front-Channel Logout ——(可選)定義一個前端渠道退出登錄機制(在 RP 頁面上不使用 OP iframe)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Back-Channel Logout ——(可選)定義一個退出登錄機制,直接使用 back-channel 在 OP 和 RP 溝通以退出登錄","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OpenID Connect Federation ——(可選)定義 OP 和 RP 集合如何通過使用聯合操作建立信任","attrs":{}}]}]}],"attrs":{}},{"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","marks":[{"type":"strong","attrs":{}}],"text":"注:","attrs":{}},{"type":"text","text":" OP = OpenID Provider,OpenID 提供商。RP = Relying Party,依賴方。","attrs":{}}]},{"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 爲基礎的依賴方實現的獨立服務:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://openid.net/specs/openid-connect-basic-1_0.html","title":"","type":null},"content":[{"type":"text","text":"基礎客戶端實現指南","attrs":{}}]},{"type":"text","text":":簡化核心功能子集,用於以 Web 爲基礎的依賴方,使用 OAuth 代碼流","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://openid.net/specs/openid-connect-implicit-1_0.html","title":"","type":null},"content":[{"type":"text","text":"隱式客戶端實現指南","attrs":{}}]},{"type":"text","text":":簡化核心功能子集,用於以 Web 爲基礎的依賴方,使用 OAuth 隱式流","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/02/0263bf9cdbd726421eb91f6e3be2a586.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"引用","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1","title":"","type":null},"content":[{"type":"text","text":"It's Time for OAuth 2.1","attrs":{}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://stormpath.com/blog/beginners-guide-jwts-in-java","title":"","type":null},"content":[{"type":"text","text":"A Beginner's Guide to JWTs in Java","attrs":{}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://oauth.net/articles/authentication/","title":"","type":null},"content":[{"type":"text","text":"User Authentication with OAuth 2.0","attrs":{}}]}]}]}],"attrs":{}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章