天天看點

Identity Server 4 預備知識 -- 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是建立在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.

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

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

這裡的資源所有者(Resource Owner), 他擁有通路API資源的權限, 并且他還可以委派權限(delegate)給其他應用來通路API. 資源所有者通常是可以使用浏覽器的人.

被保護的資源(Protected Resource)就是資源所有者擁有權限去通路的元件, 它可以是很多種形式的, 但是web API的形式還是最常見的.

用戶端(Client)應用就是代表資源所有者通路被保護資源的一個軟體. 注意它既不是指浏覽器, 也不是指給你錢讓你開發軟體的人. 在OAuth2裡面, 它是指被保護的API資源的消費者.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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的流程如下:

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

另外一張彩色圖:

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

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

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的時候一同介紹.