Identity Server 4 預備知識 -- OAuth 2.0 簡介

solenovex發表於2018-06-25

OAuth 2.0 簡介

OAuth有一些定義:

OAuth 2.0是一個委託協議, 它可以讓那些控制資源的人允許某個應用以代表他們來訪問他們控制的資源, 注意是代表這些人, 而不是假冒或模仿這些人. 這個應用從資源的所有者那裡獲得到授權(Authorization)access token, 隨後就可以使用這個access token來訪問資源.

(這裡提到的假冒或模仿就是指在客戶端複製一份使用者名稱和密碼,從而獲取相應的許可權)。

OAuth 2.0是一個開放的協議, 它允許使用簡單和標準的方法從Web, 移動或桌面應用來進行安全的授權(Authorization).

 

從這些定義可以看出來, OAuth2 是關於授權(Authorization)的,  客戶端應用可以請求access token, 使用這個token就可以訪問API資源了.

因為有很多種類客戶端應用的存在, 例如ASP.NET Core MVC, Angular, WPF 等等, 它們都是不同的應用型別, 所以, OAuth2 定義了不同型別的客戶端應用應該如何安全的完成授權. OAuth2標準還定義了一些端點, 並且定義了針對不同型別的客戶端應用如何使用這些端點.

Identity Server 4 和 Azure AD 都實現了OAuth 2.0 標準.

但是上面提到的access token只能用來訪問資源, 它無法被用來登入客戶端應用. 登入這種操作叫做認證/身份驗證(Authentication), 而OpenID Connect則可以完成這項工作.

 

OpenID Connect 簡介

OpenID Connect是建立在OAuth2協議上的一個簡單的身份標識層, 所以OpenID Connect相容OAuth2. 

使用OpenID Connect, 客戶端應用可以請求一個叫identity token的token, 它會和access token一同返回給客戶端應用. 這個identity token就可以被用來登入客戶端應用程式, 而這個客戶端應用還可以使用access token來訪問API資源.

OpenID Connect還定義了一個UserInfo端點, (OAuth2定義了Authorization端點和Token端點)它允許客戶端應用獲取使用者的額外資訊. 

此外它還定義了不同型別的應用如何從身份識別提供商(IDP)安全的獲取這些token.

 

綜上, OpenID Connect是更高階的協議, 它擴充套件並替代了OAuth2. 儘管現在我們經常說我們在使用OAuth2來保護API, 其實更準確的說, 大多數情況下, 我們使用的是OpenID Connect.

 

如果到現在還是不明白OAuth2和OpenID Connect也沒關係, 這不是幾句話就能描述清楚的東西. 本文我進一步介紹OAuth 2.0.

 

OAuth 2.0 進一步介紹

OAuth2的目標就是讓客戶端應用可以代表資源所有者(通常是使用者)來訪問被保護的資源:

  • 這裡的資源所有者(Resource Owner), 他擁有訪問API資源的許可權, 並且他還可以委派許可權(delegate)給其他應用來訪問API. 資源所有者通常是可以使用瀏覽器的人.
  • 被保護的資源(Protected Resource)就是資源所有者擁有許可權去訪問的元件, 它可以是很多種形式的, 但是web API的形式還是最常見的.
  • 客戶端(Client)應用就是代表資源所有者訪問被保護資源的一個軟體. 注意它既不是指瀏覽器, 也不是指給你錢讓你開發軟體的人. 在OAuth2裡面, 它是指被保護的API資源的消費者.

 

委拖/委派許可權

前面提到OAuth2裡面, 終端使用者可以委派他的一部分許可權給客戶端應用來代表終端使用者來訪問被保護的資源. 但是要完成這件事, 還需要一個橋樑來連線客戶端應用和被保護資源. 這個元件叫做授權伺服器(Authorization Server, AS). 這個授權伺服器也許就是資源伺服器, 但是大多數情況下它們是不同的伺服器.

授權伺服器(AS)是被受保護的資源所信任的, 它可以發行具有特定目的的安全憑據給客戶端應用, 這個憑據叫做OAuth的 access token.

想要獲得access token, 客戶端應用首先要把資源所有者傳送給授權伺服器

首先客戶端需要獲得許可權, 它可能有兩種方式來獲得許可權: 可以從資源所有者那裡直接獲得許可權, 也可以讓授權伺服器作為中介, 從授權伺服器那裡間接的獲得許可權. (上面這個圖中描述的是從資源授權者直接獲得許可權的流程).

如果使用授權伺服器作為中介的話, 客戶端需要把資源所有者傳送到授權伺服器(可以理解為終端使用者使用的瀏覽器被重定向到了授權伺服器), 然後資源所有者在這可以對客戶端應用進行授權. 

這時資源所有者要通過身份認證進入授權伺服器, 通常還會有一個是否同意授權客戶端應用請求的選項, 點選同意後就授權了. 而從客戶端應用的角度講呢, 它可以向資源所有者請求他一部分的功能和範圍(scope), 在將來, 資源所有者可能會逐漸減少它所擁有的功能和範圍.

到這裡, 上面寫的這個動作/東西叫做授權(authorization grant).

一旦執行了授權動作也就是客戶端得到了授權(這個授權是一個可以代表資源所有者許可權的憑據), 客戶端便可以從授權伺服器請求access token了. 這個access token就可以被用來訪問被保護的資源了.

下圖是使用授權伺服器作為中介的流程圖, 除了授權, 其它部分和上圖表達的都是一個意思:

 

授權 Authorization Grant

授權 (authorization grant) 是一個代表著資源所有者許可權的憑據, 它可以被客戶端應用來獲取access token. OAuth2裡面定義了4種型別的授權, 分別是: auhtorization code, implicit, resource owner password credentials, client credentials. OAuth2還定義了一個擴充套件機制以便定義其它的授權型別. 

用一句話描述就是, 授權(Authorization Grant)就是獲取token的方法.

1. Authorization Code

Authorization Code是使用授權伺服器作為客戶端和資源所有者的中介來獲取的. 所以這裡不是採用直接從資源所有者獲得授權的方式, 而是採用授權伺服器作為中介的方式. 在授權伺服器把資源所有者送回到(重定向)客戶端的時候帶著這個臨時的憑據: authorization code (我暫時叫它授權碼吧), 它就代表著資源所有者委託給客戶端應用的許可權.

Authorization code在安全方面有一些重要的優點: 可以對客戶端應用進行身份認證; access token是直接傳送到客戶端應用的, 不經過資源所有者的瀏覽器, 所以不會暴露access token給外界, 包括資源所有者.

 

2. Implicit

Implicit, 我叫它隱式授權吧. 它是Authorization Code的一個簡化版本, 它針對瀏覽器內的客戶端應用(例如js, angular的應用)進行了優化. 在implicit流程裡, 沒有給客戶端傳送授權碼(authorization code), 而是直接給它傳送了access token. 之所以叫這種授權型別implicit, 是因為流程裡並沒有發行任何中間憑據.

在implicit流程裡發行access token的時候, 授權伺服器並沒有對客戶端應用進行身份認證. 某些情況下, 客戶端的身份可以通過帶著access token重定向回客戶端的URI來驗證. acces token可能會暴露給任何使用該瀏覽器的人或者應用.

Implicit授權確實可以提高瀏覽器內應用的響應性和效率, 畢竟它減少了來回往返的次數. 但是方便可能會帶來風險, 建議如果可以的話儘量使用Authorization Code, 當然這個需要自己去權衡.

 

3. Resource Owner Password Credentials

Resource Owner Password Credentials, 資源所有者密碼憑據. 顧名思義, 可以直接使用密碼憑據(使用者名稱和密碼)作為授權來獲得access token. 只有當資源所有者和客戶端之間高度信任的時候並且其它授權方式不可用的時候才可以使用這種授權方式.

這裡資源所有者的憑據只應該用於一次請求並用於交換access token. 這種授權方式可以讓客戶端免於儲存資源所有者的憑據(如果以後還需要使用的話), 通過交換一個長期有效的access token或refresh token都可以達到這種效果.

 

4. Client Credentials

Client Credentials. 有時候, 資源或者叫資源伺服器並不屬於某個終端使用者, 也就是沒有資源所有者對該資源負責. 但是客戶端應用肯定還是要訪問這些資源, 這時候就只能使用Client Credentials這種授權方式了.

 

OAuth 2.0 的角色和元件

OAuth2的4個角色前面已經介紹過, 分別是: 資源所有者 Resource Owner, 客戶端 Client, 被保護資源 Protected Resource, 和 授權伺服器 Authorization Server.

而OAuth2的元件, 前面也都有提到過, 它們是: Access Token, Refresh TokenScope (範圍).

下面簡單介紹下這幾個元件.

Access Token: 有時候只被叫做token, 它是用來訪問被保護資源的憑據. 它是一個字串, 它代表了給客戶頒發的授權, 也就是委託給客戶的許可權. OAuth2本身並沒有對access token的格式或內容進行定義. 但是access token裡面要描述出資源所有者授予的訪問許可權的範圍和持續時間.

Access Token 通常對客戶端應用是不透明的, 也就是說客戶端無需去檢視access token. 客戶端的任務就是把它展示給被保護的資源. 其實access token在整個OAuth2系統裡對任何角色都是不透明的, 授權伺服器的任務只是發行token, 而被保護資源的任務是驗證token. 但是它們都必須理解access token的構成, 並知道access token代表了什麼. 而客戶端對於access token應該是完全健忘的.

Scopes: OAuth2的scope表示被保護資源那裡的一套許可權. 在OAuth2裡面, scope用區分大小寫的字串表示, 可以用空格作為分隔符來表示多個scope. 這些字串由授權伺服器來定義. 而scope字串的格式和結構在OAuth2裡並沒有定義.

Scope對於限制客戶端應用的訪問許可權有很重要的作用. 客戶端應用可以請求一些scopes, 而授權伺服器可以允許資源所有者授權或者拒絕特定的scopes. Scope還具有疊加性.

Refresh Token: Refresh Token是用來獲得Access Token的憑據. 和acces token差不多, refresh token也是由授權伺服器發行給客戶端應用的, 客戶端不知道也不關心refresh token裡面有啥. 但與access token不同的是, refresh token不會被髮送給被保護的資源. 客戶端是用refresh token來請求新的access token (尤其是當現在的access token過期或者失效時), 但這個過程就不需要資源所有者的參與了. Refresh Token是可選的, 授權伺服器會酌情發行refresh token, 如果需要的話, refresh token是在發行access token一同返回的.

此外refresh token還具備讓客戶端應用逐漸降低訪問許可權的能力.

通過refresh token來取得新的access token的流程如下:

另外一張彩色圖:

這張彩圖的中文意思是: 客戶端使用當前access token訪問被保護資源的時候, access token失效或者過期了, 這是從被保護資源返回了一個錯誤響應; 然後客戶端使用refresh token向授權伺服器請求了一個新的access token; 得到新的access token後, 客戶端使用新的access token請求被保護資源, 這時資源就可以被正常的返回給客戶端了.

 

OAuth 2.0的端點

OAuth2定義了一套端點(Endpoint), 端點就是web伺服器的一個訪問路徑URI.

OAuth2定義的端點有授權端點, Token端點, 它們都在授權伺服器上.

OAuth2沒有定義這些端點URI應該如何被發現和文件的結構.

授權端點(authorization endpoint)是用來和資源所有者互動的, 資源所有者在這裡進行登入(身份認證), 然後通過該端點可以對客戶端進行授權(authorization grant). 授權伺服器首先要驗證資源所有者的身份, 但是驗證的方式並不在OAuth2的協議範圍內.

Token端點(token endpoint), 客戶端通過向token端點展示它的授權(auhtorization grant)或refresh token來獲取access token. 除了implicit之外所有的授權型別都需要使用該端點, 因為implicit的access token是直接發行的.

 

本篇文章先到這. 下篇文章再簡單介紹一下OpenId Connect.

那四種授權型別具體的詳細流程將在介紹Identity Server 4的時候一同介紹.

 

相關文章