第三方應用程式在無法取得使用者名稱、密碼的情況下,想對社交網站請求使用者私人資源,現今最常見的方案是採用OAuth2,而作為OAuth2客戶端,只要遵守社交網站規範的流程就可以了。

若進一步想瞭解授權伺服器、資源伺服器的具體實作,此時,我們該怎麼面對一大堆的觀念、術語,以及參數呢?

從基本驗證到客戶端憑證

OAuth2授權的框架,主要規範於RFC6749。從核心概念來看,對於客戶端(Client)與資源擁有者(Resource Owner)之間授權的流程,會獨立出來──由授權伺服器(Authorization Server)核發存取令牌(Access Token)給客戶端,而客戶端向資源擁有者提出請求時,必須出示存取令牌,接著,資源擁有者可以透過令牌來取得相關授權資訊,然後,再決定是否允許客戶端存取受保護的資源(Protected Resources)。

雖然,資源伺服器最終都是看存取令牌做事,不過,該如何核發令牌?

OAuth2有許多角色定義(方才只提到部份),並依它們之間的互動方式,規範出四種授權類型流程(Grant Type Flow),其中涉及了大量參數,然而,初次接觸OAuth2的開發者,經常又從授權碼(Authorization Code)的類型開始認識,這時,大家應該都曾有瞬間墜入五里霧的感覺。

在採用OAuth2的場合之前,更簡單的作法,其實是運用基本(Basic)驗證的場合,像是有個伺服器,必須具有憑證才能存取,基於名稱、密碼的基本驗證就夠用了。

不過,如果有多臺伺服器都有限制存取的需求,每臺伺服器都須執行名稱、密碼驗證,就會顯得麻煩了,這時,就可考慮OAuth2的客戶端憑證(Client Credentials)核發流程。

而在OAuth2當中,使用者(User)與客戶端是分離的兩個概念。使用者通常是個擁有帳戶的人,客戶端是指某個應用程式(前端網頁、App、伺服器等),在OAuth2客戶端憑證中,基本上,沒有使用者參與,而且,通常也不會有Role-based存取控制中的角色概念,取而代之的是範疇(scope)──客戶端會被授予範疇,類似Role-based存取控制中,使用者會被授予角色。

OAuth2客戶端憑證就像是基本驗證的延伸,每臺要限制存取的伺服器上,會設定哪些資源只允許具有某些範疇的客戶端存取。

而這類似於Role-based得存取控制中,某些資源只允許具有某些角色的使用者存取,客戶端必須提供存取令牌,伺服器依令牌取得範圍(scope)資訊,從而決定是否可以存取資源。

因為OAuth2客戶端憑證沒有使用者參與,適用於內部伺服器之間的資源存取,對授權伺服器請求存取令牌時,必須提供客戶端ID與密鑰(Secret)──前者像是社交網站上要接API時的應用程式名稱,後者就像是應用程式密鑰了。

擁有使用者時的密碼憑證

當授權過程涉及使用者,有些資源會基於使用者、角色來進行存取控制,OAuth2提供了密碼憑證(Password Credentials)核發類型,某些程度上,也是最簡單、容易理解的類型,因為就像是傳統驗證授權的延伸,使用者在客戶端輸入名稱、密碼,客戶端對授權伺服器請求核發存取令牌,在資源伺服器上,就可依令牌取得使用者的角色等資訊,決定是否符合某資源的角色設定。

除了使用者名稱、密碼之外,密碼憑證核發的類型在請求核發存取令牌時,也必須同時提供客戶端ID與密鑰,授權伺服器會依此決定客戶端被授予的範疇,因此除了依角色來限制資源存取之外,運用OAuth2密碼憑證時,還可以為不同客戶端設定各自的資源權限。

運用密碼憑證核發流程的情境,通常是客戶端與服務屬於同一個單位,該單位本身就擁有使用者的帳戶資訊,由於服務伺服器只要認同存取令牌就可以存取,也能用來實現 Single Sign-On,也就是一次登入,就可使用各個獨立服務的功能。

在採用密碼憑證核發類型時,授權伺服器可以決定是否同時核發更新令牌(Refresh Token)──其有效期比存取令牌來得長,可在存取令牌過期之後,無需使用者提供名稱、密碼下,直接透過更新令牌來取得新的存取令牌,因此可用來實作自動登入之類的功能。

適用第三方應用的隱含與授權碼

如果我手中擁有資源、使用者帳戶,第三方應用程式想要存取使用者私有的資源,我不能私下給第三方應用程式使用者名稱、密碼,使用者也不會給這些敏感資訊,怎麼辦呢?這時,可以採用隱含(Implicit)或授權碼授權類型,因為在不提供使用者名稱、密碼下,又要能授予權限,因此流程上就繁複許多。

採取隱含與授權碼類型時,第三方應用程式必須能在我這邊設定應用程式名稱、密鑰,以及重導(Redirect)網址,客戶端必須能聽從重導指示(通常是個瀏覽器),還會有個第三方應用伺服器。而第三方應用伺服器,會附上redirect-uri參數(值必須與應用程式設定的重導網址相同),將客戶端重導至授權伺服器,等到使用者在輸入名稱、密碼後,確認授予第三方應用程式的範疇,接下來的流程,則依隱含與授權碼而不同。

在隱含授權類型時,授權伺服器直接核發存取令牌,並重導至redirect-uri指定的位置,此時,所進行的形式,會像是下列這樣:https://3rdsvr/app.html#access_token=84f9-749e-45db&token_type=bearer&expires_in=43199&scope=message,其中的#分段,包含了存取令牌相關資訊,而瀏覽器不會發送#分段後的資訊,因此,在app.html之中,必須有JavaScript,以便提取#分段中的存取令牌,再用令牌向資源伺服器進行請求。

因此,隱含授權是針對只能在前端(瀏覽器)執行的應用程式,雖然,OAuth2的規範要求核發流程必須在加密連線中進行,然而存取令牌就直接附在重導網址上頭,依然是有安全上的疑慮,這可以採取授權碼流程來避免。

授權碼流程在重導瀏覽器時,會附上的是授權碼(而不是存取令牌),形式會像是https://3rdsvr/app?code=61vXSV,第三方應用程式伺服器取得code請求參數後,在後端對授權伺服器請求存取令牌,整個過程中,瀏覽器不會接觸到存取令牌,從而避免了存取令牌曝露在前端的問題。

依需求而疊加的概念

若一開始接從OAuth2的授權碼類型開始瞭解,就會驟然面臨大量術語,像是:第三方、客戶端、密鑰(往往與使用者名稱、密碼混淆)、資源擁有者、範疇(往往與角色混淆)、重導等,實際上,這些術語觀念,是從簡單的需求到複雜的考量,而逐一疊加上去的。

開發者可以從簡單的客戶端憑證開始,逐一認識更繁複的授權類型。這麼一來,除了不用突然面對大量術語之外,我們也可以明確地知道:哪些術語是前一個觀念的延伸,哪些設定又會是基於前一個授權類型的設定而來;之後在真正實作時,也能明確地知道,哪個授權類型,才是真正符合實際的授權需求。

 

專欄作者

熱門新聞

Advertisement