授權服務概觀

Keycloak 支援細緻的授權政策,並能夠結合不同的存取控制機制,例如

  • 基於屬性的存取控制 (ABAC)

  • 基於角色的存取控制 (RBAC)

  • 基於使用者的存取控制 (UBAC)

  • 基於上下文的存取控制 (CBAC)

  • 基於規則的存取控制

    • 使用 JavaScript

  • 基於時間的存取控制

  • 透過服務提供者介面 (SPI) 支援自訂存取控制機制 (ACM)

Keycloak 基於一組管理 UI 和 RESTful API,並提供必要的方法來為您的受保護資源和範圍建立權限、將這些權限與授權政策關聯,並在您的應用程式和服務中強制執行授權決策。

資源伺服器(提供受保護資源的應用程式或服務)通常依賴某種資訊來決定是否應授予對受保護資源的存取權。對於基於 RESTful 的資源伺服器,該資訊通常從安全性權杖取得,通常作為不記名權杖在對伺服器的每次請求中傳送。對於依賴會話來驗證使用者的 Web 應用程式,該資訊通常儲存在使用者會話中,並從該處擷取每次請求。

資源伺服器通常僅根據基於角色的存取控制 (RBAC) 執行授權決策,其中會檢查嘗試存取受保護資源的使用者被授予的角色,是否與對應到這些相同資源的角色相符。雖然角色非常有用並被應用程式使用,但它們也有一些限制

  • 資源和角色緊密耦合,對角色的變更(例如新增、移除或變更存取內容)可能會影響多個資源

  • 對您的安全性需求的變更可能會導致應用程式程式碼發生深度變更,以反映這些變更

  • 根據您的應用程式大小,角色管理可能會變得困難且容易出錯

  • 它不是最靈活的存取控制機制。角色不代表你是誰,並且缺乏上下文資訊。如果您被授予角色,您至少有一些存取權。

考慮到今天我們需要考慮異質環境,其中使用者分佈在不同的區域,具有不同的當地政策,使用不同的裝置,並且對資訊共用有很高的需求,Keycloak 授權服務可以透過以下方式協助您改進應用程式和服務的授權功能

  • 使用細緻的授權政策和不同的存取控制機制來保護資源

  • 集中式資源、權限和政策管理

  • 集中式政策決策點

  • 基於一組基於 REST 的授權服務的 REST 安全性

  • 授權工作流程和使用者管理存取權

  • 基礎架構可協助避免跨專案的程式碼複製(和重新部署),並快速適應您安全性需求的變更。

架構

Keycloak AuthZ architecture overview

從設計的角度來看,授權服務基於一組定義完善的授權模式,提供以下功能

  • 政策管理點 (PAP)

    提供基於 Keycloak 管理主控台的一組 UI,以管理資源伺服器、資源、範圍、權限和政策。部分此操作也可透過使用 保護 API 遠端完成。

  • 政策決策點 (PDP)

    提供可分發的政策決策點,授權請求會傳送到該點,並根據所請求的權限評估政策。如需更多資訊,請參閱取得權限

  • 政策執行點 (PEP)

    為不同的環境提供實作,以實際在資源伺服器端強制執行授權決策。Keycloak 提供一些內建的 政策執行器

  • 政策資訊點 (PIP)

    基於 Keycloak 驗證伺服器,您可以在評估授權政策期間從身分和執行階段環境取得屬性。

授權流程

三個主要流程定義了了解如何使用 Keycloak 為您的應用程式啟用細緻授權的必要步驟

  • 資源管理

  • 權限和政策管理

  • 政策執行

資源管理

資源管理包含定義受保護內容的所有必要步驟。

Resource management overview

首先,您需要指定 Keycloak 您想要保護的內容,這通常表示 Web 應用程式或一組或多個服務。如需資源伺服器的更多資訊,請參閱術語

資源伺服器使用 Keycloak 管理主控台進行管理。您可以在該處啟用任何已註冊的用戶端應用程式作為資源伺服器,並開始管理您要保護的資源和範圍。

Resource Server overview

資源可以是網頁、RESTFul 資源、檔案系統中的檔案、EJB 等等。它們可以表示一組資源(就像 Java 中的類別),或者它們可以表示單個且特定的資源。

例如,您可能有一個銀行帳戶資源,表示所有銀行帳戶,並使用它來定義適用於所有銀行帳戶的授權政策。但是,您可能想要為Alice 帳戶(屬於客戶的資源實例)定義特定政策,其中只有擁有者才能存取某些資訊或執行操作。

可以使用 Keycloak 管理主控台或保護 API 來管理資源。在後一種情況下,資源伺服器能夠遠端管理其資源。

範圍通常表示可以對資源執行的操作,但它們不限於此。您也可以使用範圍來表示資源內的一個或多個屬性。

權限和政策管理

定義資源伺服器和您要保護的所有資源後,您必須設定權限和政策。

此流程包含定義管理您資源的安全性和存取需求的所有必要步驟。

Permission and policy management overview

政策定義必須滿足的條件才能存取或對某物(資源或範圍)執行操作,但它們並未與它們保護的內容繫結。它們是通用的,可以重複使用以建立權限或更複雜的政策。

例如,要僅允許具有「高級使用者」角色的使用者存取一組資源,您可以使用 RBAC(基於角色的存取控制)。

Keycloak 提供一些內建的政策類型(以及它們各自的政策提供者),涵蓋最常見的存取控制機制。您甚至可以根據使用 JavaScript 編寫的規則建立政策。

定義政策後,您可以開始定義權限。權限與它們保護的資源耦合。在此處,您可以指定要保護的內容(資源或範圍)以及必須滿足才能授予或拒絕權限的政策。

政策執行

政策執行包含將授權決策實際強制執行到資源伺服器的必要步驟。這是透過在資源伺服器上啟用政策執行點或 PEP 來實現的,該點能夠與授權伺服器通訊、請求授權資料,並根據伺服器傳回的決策和權限來控制對受保護資源的存取。

PEP overview

Keycloak 提供一些內建的 政策執行器 實作,您可以使用它們來保護您的應用程式,具體取決於它們執行的平台。

授權服務

授權服務包含下列 RESTFul 端點

  • 令牌端點

  • 資源管理端點

  • 權限管理端點

這些服務中的每一個都提供了特定的 API,涵蓋授權流程中涉及的不同步驟。

令牌端點

OAuth2 客戶端(例如前端應用程式)可以使用令牌端點從伺服器取得存取令牌,並使用這些令牌來存取受資源伺服器(例如後端服務)保護的資源。同樣地,Keycloak 授權服務提供了 OAuth2 的擴展功能,允許根據與所請求的資源或範圍相關聯的所有原則處理來發放存取令牌。這表示資源伺服器可以根據伺服器授予並由存取令牌持有的權限來強制存取其受保護的資源。在 Keycloak 授權服務中,具有權限的存取令牌稱為請求方令牌(Requesting Party Token),簡稱 RPT。

其他資源
保護 API

保護 API 是一組符合 UMA 標準的端點,為資源伺服器提供操作,協助它們管理其資源、範圍、權限和與之相關的原則。只有資源伺服器才允許存取此 API,並且還需要 uma_protection 範圍。

保護 API 提供的操作可以分為兩個主要群組

  • 資源管理

    • 建立資源

    • 刪除資源

    • 依 ID 查找

    • 查詢

  • 權限管理

    • 發出權限票證

預設情況下,遠端資源管理已啟用。您可以使用 Keycloak 管理控制台變更此設定,並且只允許透過控制台進行資源管理。

當使用 UMA 協定時,保護 API 發出的權限票證是整個授權流程的重要部分。如後續章節所述,它們代表客戶端請求的權限,並且會被傳送到伺服器,以取得最終令牌,該令牌包含在評估與所請求資源和範圍相關聯的權限和原則時授予的所有權限。

其他資源

術語

在深入探討之前,了解 Keycloak 授權服務引入的這些術語和概念非常重要。

資源伺服器

根據 OAuth2 術語,資源伺服器是託管受保護資源並能夠接受和回應受保護資源請求的伺服器。

資源伺服器通常依賴某種資訊來決定是否應授予對受保護資源的存取權。對於基於 RESTful 的資源伺服器,該資訊通常攜帶在安全令牌中,通常以持票人令牌形式與發送到伺服器的每個請求一起發送。依賴會話來驗證使用者的 Web 應用程式通常將該資訊儲存在使用者的會話中,並從那裡為每個請求檢索它。

在 Keycloak 中,任何機密客戶端應用程式都可以充當資源伺服器。此客戶端的資源及其各自的範圍受到一組授權原則的保護和管理。

資源

資源是應用程式和組織資產的一部分。它可以是一組或多個端點、經典的 Web 資源(例如 HTML 頁面)等等。在授權原則術語中,資源是被保護的物件

每個資源都有一個唯一的識別符,可以代表單個資源或一組資源。例如,您可以管理一個銀行帳戶資源,該資源代表並定義所有銀行帳戶的一組授權原則。但是您也可以有一個名為愛麗絲的銀行帳戶的不同資源,該資源代表單個客戶擁有的單個資源,該資源可以擁有自己的一組授權原則。

範圍

資源的範圍是對資源執行可能進行的有限程度的存取。在授權原則術語中,範圍是邏輯上可以應用於資源的潛在多個動詞之一。

它通常指示可以使用給定資源做什麼。範圍的範例包括檢視、編輯、刪除等等。但是,範圍也可能與資源提供的特定資訊相關。在這種情況下,您可以擁有一個專案資源和一個成本範圍,其中成本範圍用於定義使用者存取專案成本的特定原則和權限。

權限

考慮這個簡單且非常常見的權限

權限將受保護的物件與必須評估的原則相關聯,以確定是否授予存取權。

  • X 可以在資源 Z 上執行 Y

    • 其中 …​

      • X 代表一個或多個使用者、角色或群組,或它們的組合。您也可以在這裡使用宣告和內容。

      • Y 代表要執行的動作,例如,寫入、檢視等等。

      • Z 代表受保護的資源,例如,「/accounts」。

Keycloak 提供了一個豐富的平台,用於建立從簡單到非常複雜的各種權限策略,即基於規則的動態權限。它提供了彈性並有助於

  • 減少程式碼重構和權限管理成本

  • 支援更靈活的安全模型,幫助您輕鬆適應安全需求的變化

  • 在執行階段進行變更;應用程式只關心受保護的資源和範圍,而不關心它們是如何受到保護的。

原則

原則定義了必須滿足的條件才能授予對物件的存取權。與權限不同,您不指定受保護的物件,而是指定必須滿足哪些條件才能存取給定物件(例如,資源、範圍或兩者)。原則與您可以使用的不同存取控制機制 (ACM) 密切相關,以保護您的資源。透過原則,您可以實作基於屬性的存取控制 (ABAC)、基於角色的存取控制 (RBAC)、基於內容的存取控制或這些控制的任何組合的策略。

Keycloak 利用原則的概念以及您如何定義它們,方法是提供聚合原則的概念,您可以在其中建立「原則的原則」,並且仍然控制評估的行為。Keycloak 授權服務中的原則實作遵循分而治之的技術,而不是編寫一個大型原則,其中包含必須滿足的所有條件才能存取給定資源。也就是說,您可以建立個別的原則,然後將它們重複用於不同的權限,並透過組合個別的原則來建立更複雜的原則。

原則提供者

原則提供者是特定原則類型的實作。Keycloak 提供內建原則,由其對應的原則提供者支援,並且您可以建立自己的原則類型來支援您的特定需求。

Keycloak 提供了一個 SPI(服務提供者介面),您可以使用它來插入您自己的原則提供者實作。

權限票證

權限票證是由使用者管理存取 (UMA) 規格定義的一種特殊類型的令牌,它提供了一個不透明的結構,其形式由授權伺服器確定。此結構代表客戶端請求的資源和/或範圍、存取內容,以及必須應用於授權資料請求(請求方令牌 [RPT])的原則。

在 UMA 中,權限票證對於支援個人對個人共享以及個人對組織共享至關重要。在授權工作流程中使用權限票證可以實現從簡單到複雜的各種情境,其中資源擁有者和資源伺服器可以根據管理這些資源存取的細微原則完全控制其資源。

在 UMA 工作流程中,權限票證由授權伺服器發給資源伺服器,資源伺服器將權限票證返回給嘗試存取受保護資源的客戶端。一旦客戶端收到票證,它就可以透過將票證發回授權伺服器來請求 RPT(包含授權資料的最終令牌)。

有關權限票證的更多資訊,請參閱使用者管理存取UMA 規格。

入門

對於某些應用程式,您可以查看以下資源以快速開始使用 Keycloak 授權服務

管理資源伺服器

根據 OAuth2 規範,資源伺服器是託管受保護資源的伺服器,能夠接受並回應受保護的資源請求。

在 Keycloak 中,資源伺服器提供了一個豐富的平台,使其能夠對其受保護的資源進行細粒度的授權,其中授權決策可以基於不同的存取控制機制。

任何用戶端應用程式都可以設定為支援細粒度的權限。這樣做,在概念上您就將用戶端應用程式轉變為資源伺服器。

建立用戶端應用程式

啟用 Keycloak 授權服務的第一步是建立您想要轉變為資源伺服器的用戶端應用程式。

步驟
  1. 點擊 用戶端

    用戶端

    Clients

  2. 在此頁面上,點擊 建立用戶端

    新增用戶端

    Add Client

  3. 輸入用戶端的 用戶端 ID。例如,my-resource-server

  4. 點擊 下一步

  5. 用戶端驗證 切換為開啟。

  6. 點擊 儲存

  7. 輸入應用程式的 根 URL。例如

    http://${host}:${port}/my-resource-server
  8. 點擊 儲存。用戶端已建立,並開啟用戶端設定頁面。會顯示類似以下的頁面

    用戶端設定

    Client Settings

啟用授權服務

您可以將您的 OIDC 用戶端轉換為資源伺服器,並啟用細粒度的授權。

步驟
  1. 在用戶端設定頁面中,向下捲動至 功能設定 區段。

  2. 啟用授權 切換為 開啟

  3. 點擊 儲存

    啟用授權服務

    Enabling authorization services

    此用戶端會顯示一個新的「授權」標籤。點擊 授權 標籤,會顯示類似以下的頁面

    資源伺服器設定

    Resource server settings

「授權」標籤包含額外的子標籤,涵蓋您必須遵循以實際保護您的應用程式資源的不同步驟。每個標籤都由本文件中特定的主題分別介紹。但以下是每個標籤的快速描述

  • 設定

    您資源伺服器的通用設定。有關此頁面的更多詳細資訊,請參閱 資源伺服器設定 章節。

  • 資源

    從此頁面,您可以管理您應用程式的 資源

  • 授權範圍

    從此頁面,您可以管理範圍

  • 原則

    從此頁面,您可以管理授權原則,並定義必須滿足以授予權限的條件。

  • 權限

    從此頁面,您可以透過將它們與您建立的原則連結,來管理您受保護資源和範圍的權限

  • 評估

    從此頁面,您可以模擬授權請求,並檢視您定義的權限和授權原則的評估結果。

  • 匯出設定

    從此頁面,您可以將授權設定匯出到 JSON 檔案。

資源伺服器設定

在「資源伺服器設定」頁面上,您可以設定原則強制執行模式、允許遠端資源管理,以及匯出授權組態設定。

  • 原則強制執行模式

    指定處理傳送至伺服器的授權請求時,如何強制執行原則。

    • 強制執行

      (預設模式) 即使沒有與給定資源相關聯的原則,也會預設拒絕請求。

    • 允許

      即使沒有與給定資源相關聯的原則,也允許請求。

    • 已停用

      停用所有原則的評估,並允許存取所有資源。

  • 決策策略

    此組態會變更原則評估引擎如何根據所有評估權限的結果,來決定是否應授予資源或範圍。 肯定表示至少一個權限必須評估為肯定決策,才能授予資源及其範圍的存取權。 一致表示所有權限都必須評估為肯定決策,最終決策才能也為肯定。例如,如果同一資源或範圍的兩個權限發生衝突 (其中一個權限授予存取權,而另一個權限拒絕存取權),如果選擇的策略是 肯定,則會授予資源或範圍的權限。否則,任何權限的單一拒絕也會拒絕對資源或範圍的存取。

  • 遠端資源管理

    指定資源是否可由資源伺服器遠端管理。如果為 false,則資源只能從管理控制台管理。

預設組態

當您建立資源伺服器時,Keycloak 會為您新建立的資源伺服器建立預設組態。

預設組態包含

  • 代表您應用程式中所有資源的預設受保護資源。

  • 始終授予存取此原則所保護資源的原則。

  • 根據預設原則管理對所有資源存取權的權限。

預設受保護資源稱為 預設資源,如果您瀏覽至 資源 標籤,即可檢視它。

預設資源

Default resource

此資源定義一個 類型,即 urn:my-resource-server:resources:default 和一個 URI /*。在這裡,URI 欄位定義一個萬用字元模式,向 Keycloak 指示此資源代表您應用程式中的所有路徑。換句話說,當為您的應用程式啟用原則強制執行時,將在授予存取權之前檢查與資源相關聯的所有權限。

先前提及的 類型 定義一個值,可用於建立必須套用至預設資源或您使用相同類型建立的任何其他資源的類型化資源權限

預設原則稱為 僅來自領域原則,如果您瀏覽至 原則 標籤,即可檢視它。

預設原則

Default policy

此原則是基於 JavaScript 的原則,定義一個始終授予存取此原則所保護資源的條件。如果您點擊此原則,您會看到它定義的規則如下

// by default, grants any permission associated with this policy
$evaluation.grant();

最後,預設權限稱為 預設權限,如果您瀏覽至 權限 標籤,即可檢視它。

預設權限

Default Permission

此權限是基於資源的權限,定義一組或多組套用至具有給定類型之所有資源的原則。

變更預設組態

您可以移除預設資源、原則或權限定義並建立您自己的定義,來變更預設組態。

預設資源是以 URI 建立的,該 URI 使用 /* 模式對應到您應用程式中的任何資源或路徑。在建立您自己的資源、權限和原則之前,請確保預設組態不會與您自己的設定衝突。

預設組態定義一個對應到您應用程式中所有路徑的資源。如果您要為您自己的資源撰寫權限,請務必移除 預設資源 或將其 URIS 欄位變更為您應用程式中更具體的路徑。否則,與預設資源相關聯的原則 (預設情況下始終授予存取權) 將允許 Keycloak 授予對任何受保護資源的存取權。

匯出和匯入授權組態

可以匯出和下載資源伺服器 (或用戶端) 的組態設定。您也可以匯入資源伺服器的現有組態檔案。當您想要為資源伺服器建立初始組態或更新現有組態時,匯入和匯出組態檔案很有幫助。組態檔案包含以下定義

  • 受保護的資源和範圍

  • 原則

  • 權限

匯出組態檔案

步驟
  1. 在選單中點擊 用戶端

  2. 點擊您建立為資源伺服器的用戶端。

  3. 點擊 匯出 標籤。

    匯出設定

    Export Settings

組態檔案會以 JSON 格式匯出並顯示在文字區域中,您可以從中複製並貼上。您也可以點擊 下載 來下載組態檔案並儲存它。

匯入組態檔案

您可以匯入資源伺服器的組態檔案。

步驟
  1. 導覽至 資源伺服器設定 頁面。

    匯入設定

    Import Settings

  2. 點擊 匯入,然後選擇一個包含您要匯入之組態的檔案。

管理資源和範圍

資源管理是直接且通用的。建立資源伺服器後,您可以開始建立您想要保護的資源和範圍。資源和範圍可以分別透過導覽至資源授權範圍標籤頁來管理。

檢視資源

資源頁面,您會看到與資源伺服器相關聯的資源清單。

資源

Resources

資源清單提供有關受保護資源的資訊,例如

  • 類型

  • URI

  • 擁有者

  • 相關聯的範圍(如果有的話)

  • 相關聯的權限

從這個清單中,您也可以直接為要建立權限的資源點擊建立權限來建立權限。

在為您的資源建立權限之前,請確保您已經定義了您想要與權限關聯的策略。

建立資源

建立資源是直接且通用的。您主要關注的是您所建立資源的粒度。換句話說,可以建立資源來表示一組或多個資源,而您定義它們的方式對於管理權限至關重要。

要建立新資源,請點擊建立資源

新增資源

Add resource

在 Keycloak 中,資源定義了一小組資訊,這些資訊對於不同類型的資源是通用的,例如

  • 名稱

    一個人類可讀且唯一描述此資源的字串。

  • 類型

    一個唯一識別一組或多個資源類型的字串。類型是一個字串,用於將不同的資源實例分組。例如,自動建立的預設資源的預設類型為 urn:resource-server-name:resources:default

  • URI

    提供資源位置/位址的 URI。對於 HTTP 資源,URI 通常是用來服務這些資源的相對路徑。

  • 範圍

    一個或多個與資源關聯的範圍。

資源屬性

資源可能具有與之關聯的屬性。這些屬性可以用來提供有關資源的額外資訊,並在評估與資源關聯的權限時,向策略提供額外的資訊。

每個屬性都是一個鍵值對,其中值可以是一組或多個字串。可以為一個屬性定義多個值,方法是用逗號分隔每個值。

類型化資源

資源的類型欄位可以用來將不同的資源分組在一起,以便可以使用一組通用的權限來保護它們。

資源擁有者

資源也有擁有者。預設情況下,資源由資源伺服器擁有。

但是,資源也可以與使用者關聯,因此您可以根據資源擁有者建立權限。例如,只有資源擁有者才被允許刪除或更新給定的資源。

遠端管理資源

資源管理也透過保護 API 公開,以允許資源伺服器遠端管理其資源。

當使用保護 API 時,可以實作資源伺服器來管理其使用者擁有的資源。在這種情況下,您可以指定使用者識別碼,將資源配置為屬於特定使用者。

Keycloak 為資源伺服器提供對其資源的完全控制。在未來,我們應該能夠允許使用者控制自己的資源,以及批准授權請求和管理權限,特別是當使用 UMA 協議時。

管理策略

如前所述,策略定義了在授予對象存取權之前必須滿足的條件。

步驟
  1. 點擊策略標籤頁以檢視與資源伺服器關聯的所有策略。

    原則

    Policies

    在這個標籤頁上,您可以檢視先前建立的策略清單,以及建立和編輯策略。

要建立新策略,請點擊建立策略,然後從清單中選取策略類型。

本節將說明有關每種策略類型的詳細資訊。

基於使用者的策略

您可以使用此類型的策略來定義權限的條件,其中允許一組或多個使用者存取對象。

要建立新的基於使用者的策略,請在策略清單右上角的項目清單中選取使用者

新增使用者策略

Add User Policy

設定

  • 名稱

    一個人類可讀且唯一識別策略的字串。最佳做法是使用與您的業務和安全需求密切相關的名稱,以便您可以更輕鬆地識別它們。

  • 描述

    一個包含有關此策略詳細資訊的字串。

  • 使用者

    指定此策略授予哪些使用者存取權。

  • 邏輯

    此策略在評估其他條件後套用的邏輯。

其他資源

基於角色的策略

您可以使用此類型的策略來定義權限的條件,其中允許一組或多個角色存取對象。

預設情況下,新增到此策略的角色不會指定為必要,如果請求存取的使用者已被授予這些角色中的任何一個,則該策略將授予存取權。但是,如果您想要強制執行特定角色,您可以將特定角色指定為必要。您還可以結合必要和非必要角色,無論它們是網域角色還是用戶端角色。

當您需要更嚴格的基於角色的存取控制 (RBAC) 時,角色策略會很有用,其中必須強制執行特定角色才能授予對象的存取權。例如,您可以強制使用者同意允許用戶端應用程式(代表使用者行事)存取使用者的資源。您可以使用 Keycloak 用戶端範圍對應來啟用同意頁面,甚至強制用戶端在從 Keycloak 伺服器取得存取權杖時明確提供範圍。

要建立新的基於角色的策略,請從策略類型清單中選取角色

新增角色策略

Add Role Policy

設定

  • 名稱

    一個人類可讀且唯一描述策略的字串。最佳做法是使用與您的業務和安全需求密切相關的名稱,以便您可以更輕鬆地識別它們。

  • 描述

    一個包含有關此策略詳細資訊的字串。

  • 網域角色

    指定此策略允許哪些網域角色。

  • 用戶端角色

    指定此策略允許哪些用戶端角色。要啟用此欄位,必須先選取一個用戶端

  • 擷取角色

    預設情況下,只有授權請求隨附的權杖中可用的角色才會用來檢查使用者是否被授予角色。如果啟用此設定,策略將會忽略權杖中的角色,而是檢查與使用者關聯的任何角色。

  • 邏輯

    此策略在評估其他條件後套用的邏輯。

其他資源

定義必要角色

在建立基於角色的策略時,您可以將特定角色指定為必要。當您這樣做時,只有在請求存取的使用者被授予所有必要角色時,策略才會授予存取權。網域角色和用戶端角色都可以這樣設定。

必要角色的範例

Example of a required role

要將角色指定為必要角色,請選取您要設定為必要角色的角色的必要核取方塊。

當您的政策定義了多個角色,但只有一部分是強制性的時,必要角色會很有用。在這種情況下,您可以結合領域和用戶端角色,為您的應用程式啟用更精細的角色型存取控制 (RBAC) 模型。例如,您可以針對特定用戶端設定特定政策,並要求與該用戶端關聯的特定用戶端角色。或者,您可以強制只有在存在特定領域角色的情況下才授予存取權。您也可以在同一政策中結合這兩種方法。

基於 JavaScript 的政策

如果您的政策實作使用屬性型存取控制 (ABAC),如下列範例所示,請確保使用者無法編輯受保護的屬性,且對應的屬性為唯讀。請參閱威脅模型緩解章節中的詳細資訊。

您可以使用此類型的政策,使用 JavaScript 為您的權限定義條件。它是 Keycloak 支援的基於規則的政策類型之一,並提供根據評估 API撰寫任何政策的彈性。

若要建立新的基於 JavaScript 的政策,請在政策清單的右上角項目清單中選取 [JavaScript]。

預設情況下,JavaScript 政策無法上傳至伺服器。您應該偏好將您的 JS 政策直接部署到伺服器,如JavaScript 提供者中所述。

從已部署的 JAR 檔案建立 JS 政策

Keycloak 允許您部署 JAR 檔案,以便將指令碼部署到伺服器。請參閱JavaScript 提供者以取得更多詳細資訊。

部署指令碼後,您應該能夠從可用的政策提供者清單中選取您部署的指令碼。

範例

檢查評估內容中的屬性

以下是一個基於 JavaScript 的政策的簡單範例,該政策使用屬性型存取控制 (ABAC) 來定義基於從執行內容取得的屬性的條件

const context = $evaluation.getContext();
const contextAttributes = context.getAttributes();

if (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {
    $evaluation.grant();
}
檢查目前身分中的屬性

以下是一個基於 JavaScript 的政策的簡單範例,該政策使用屬性型存取控制 (ABAC) 來定義基於與目前身分關聯的屬性的條件

const context = $evaluation.getContext();
const identity = context.getIdentity();
const attributes = identity.getAttributes();
const email = attributes.getValue('email').asString(0);

if (email.endsWith('@keycloak.org')) {
    $evaluation.grant();
}

這些屬性是從授權請求中使用的權杖中定義的任何宣告對應而來的。

檢查授予目前身分的角色

您也可以在您的政策中使用角色型存取控制 (RBAC)。在下面的範例中,我們會檢查使用者是否被授予 keycloak_user **領域**角色

const context = $evaluation.getContext();
const identity = context.getIdentity();

if (identity.hasRealmRole('keycloak_user')) {
    $evaluation.grant();
}

或者您可以檢查使用者是否被授予 my-client-role **用戶端**角色,其中 my-client 是用戶端應用程式的用戶端 ID

const context = $evaluation.getContext();
const identity = context.getIdentity();

if (identity.hasClientRole('my-client', 'my-client-role')) {
    $evaluation.grant();
}
檢查授予使用者的角色

檢查授予使用者的領域角色

const realm = $evaluation.getRealm();

if (realm.isUserInRealmRole('marta', 'role-a')) {
    $evaluation.grant();
}

或檢查授予使用者的用戶端角色

const realm = $evaluation.getRealm();

if (realm.isUserInClientRole('marta', 'my-client', 'some-client-role')) {
    $evaluation.grant();
}
檢查授予群組的角色

檢查授予群組的領域角色

const realm = $evaluation.getRealm();

if (realm.isGroupInRole('/Group A/Group D', 'role-a')) {
    $evaluation.grant();
}
將任意宣告推送到資源伺服器

將任意宣告推送到資源伺服器,以便提供有關應如何強制執行權限的其他資訊

const permission = $evaluation.getPermission();

// decide if permission should be granted

if (granted) {
    permission.addClaim('claim-a', 'claim-a');
    permission.addClaim('claim-a', 'claim-a1');
    permission.addClaim('claim-b', 'claim-b');
}
檢查群組成員資格
const realm = $evaluation.getRealm();

if (realm.isUserInGroup('marta', '/Group A/Group B')) {
    $evaluation.grant();
}
混合不同的存取控制機制

您也可以結合多種存取控制機制。下面的範例顯示如何在同一政策中使用角色 (RBAC) 和宣告/屬性 (ABAC) 檢查。在此範例中,我們會檢查使用者是否被授予 admin 角色,或者電子郵件是否來自 keycloak.org 網域

const context = $evaluation.getContext();
const identity = context.getIdentity();
const attributes = identity.getAttributes();
const email = attributes.getValue('email').asString(0);

if (identity.hasRealmRole('admin') || email.endsWith('@keycloak.org')) {
    $evaluation.grant();
}
撰寫您自己的規則時,請記住 $evaluation 物件是一個實作 org.keycloak.authorization.policy.evaluation.Evaluation 的物件。如需有關您可以從此介面存取哪些資訊的詳細資訊,請參閱評估 API

基於時間的政策

您可以使用此類型的政策,為您的權限定義時間條件。

若要建立新的基於時間的政策,請在政策清單的右上角項目清單中選取 [時間]。

新增時間政策

Add Time Policy

組態

  • 名稱

    一個人類可讀且唯一描述策略的字串。最佳做法是使用與您的業務和安全需求密切相關的名稱,以便您可以更輕鬆地識別它們。

  • 描述

    一個包含有關此策略詳細資訊的字串。

  • 開始時間

    定義必須授予存取權的時間。只有當目前的日期/時間晚於或等於此值時,才會授予權限。

  • 到期時間

    定義必須授予存取權的時間。只有當目前的日期/時間早於或等於此值時,才會授予權限。選取 [重複] 以重複在特定的月份日期月份年份小時分鐘授予的存取權。

  • 月份日期

    定義必須授予存取權的月份日期。您也可以指定日期範圍。在這種情況下,只有當目前的月份日期介於或等於指定的兩個值之間時,才會授予權限。

  • 月份

    定義必須授予存取權的月份。您也可以指定月份範圍。在這種情況下,只有當目前的月份介於或等於指定的兩個值之間時,才會授予權限。

  • 年份

    定義必須授予存取權的年份。您也可以指定年份範圍。在這種情況下,只有當目前的年份介於或等於指定的兩個值之間時,才會授予權限。

  • 小時

    定義必須授予存取權的小時。您也可以指定小時範圍。在這種情況下,只有當目前的小時介於或等於指定的兩個值之間時,才會授予權限。

  • 分鐘

    定義必須授予存取權的分鐘。您也可以指定分鐘範圍。在這種情況下,只有當目前的分鐘介於或等於指定的兩個值之間時,才會授予權限。

  • 邏輯

    此策略在評估其他條件後套用的邏輯。

只有在滿足所有條件時才會授予存取權。Keycloak 將根據每個條件的結果執行AND運算。

其他資源

彙總政策

如前所述,Keycloak 允許您建立政策的政策,這個概念稱為政策彙總。您可以使用政策彙總來重複使用現有政策,以建立更複雜的政策,並讓您的權限與授權請求處理期間評估的政策更為分離。

若要建立新的彙總政策,請從政策類型清單中選取 [彙總]。

新增彙總政策

Add aggregated policy

假設您有一個名為「機密資源」的資源,只有來自 keycloak.org 網域和特定 IP 位址範圍的使用者才能存取。您可以建立一個包含這兩個條件的單一政策。但是,您希望重複使用此政策的網域部分,以應用於不論來源網路的權限。

您可以針對網域和網路條件建立個別政策,並根據這兩個政策的組合建立第三個政策。透過彙總政策,您可以自由組合其他政策,然後將新的彙總政策套用至您想要的任何權限。

建立彙總政策時,請注意不要在政策之間引入循環參考或相依性。如果偵測到循環相依性,您將無法建立或更新政策。

組態

  • 名稱

    描述政策的可讀且唯一的字串。我們強烈建議您使用與您的業務和安全性需求密切相關的名稱,以便您可以更輕鬆地識別它們,並且知道它們的含義。

  • 描述

    包含有關此政策的更多詳細資訊的字串。

  • 套用政策

    定義一組或多組要與彙總政策關聯的政策。若要關聯政策,您可以選取現有政策,或選取您要建立的政策類型來建立新政策。

  • 決策策略

    此權限的決策策略。

  • 邏輯

    此策略在評估其他條件後套用的邏輯。

其他資源

彙總政策的決策策略

建立彙總政策時,您也可以定義決策策略,該策略將用於根據每個政策的結果決定最終決策。

  • 一致同意

    如果未提供任何策略,則為預設策略。在這種情況下,所有政策都必須評估為正面決策,最終決策才會為正面。

  • 肯定

    在這種情況下,至少一個政策必須評估為正面決策,最終決策才會為正面。

  • 共識

    在這種情況下,正面決策的數量必須大於負面決策的數量。如果正面決策和負面決策的數量相同,則最終決策將為負面。

基於用戶端的政策

您可以使用此類型的政策來定義權限的條件,其中一組或多個用戶端被允許存取物件。

若要建立新的基於用戶端的政策,請從政策類型列表中選取 用戶端

新增用戶端政策

Add a Client Policy

設定

  • 名稱

    一個人類可讀且唯一識別策略的字串。最佳做法是使用與您的業務和安全需求密切相關的名稱,以便您可以更輕鬆地識別它們。

  • 描述

    一個包含有關此策略詳細資訊的字串。

  • 用戶端

    指定哪些用戶端具有此政策授予的基於群組的政策存取權。

  • 邏輯

    此策略在評估其他條件後套用的邏輯。

其他資源

基於群組的政策

您可以使用此類型的政策來定義權限的條件,其中一組或多個群組(及其階層)被允許存取物件。

若要建立新的基於群組的政策,請從政策類型列表中選取 群組

群組政策

Add Group Policy

設定

  • 名稱

    一個人類可讀且唯一描述策略的字串。最佳做法是使用與您的業務和安全需求密切相關的名稱,以便您可以更輕鬆地識別它們。

  • 描述

    一個包含有關此策略詳細資訊的字串。

  • 群組聲明

    指定持有群組名稱和/或路徑的權杖中的聲明名稱。通常,授權請求是根據先前發給代表某些使用者行事的用戶端的 ID 權杖或存取權杖來處理的。如果已定義,權杖必須包含一個聲明,此政策將從該聲明取得使用者所屬的群組。如果未定義,則使用者的群組會從您的領域設定中取得。

  • 群組

    允許您選取在評估權限時應由該政策強制執行的群組。新增群組後,您可以勾選 延伸至子群組 核取方塊,以將存取權延伸至該群組的子群組。如果保持未勾選,則存取限制僅適用於選取的群組。

  • 邏輯

    此策略在評估其他條件後套用的邏輯。

其他資源

延伸存取至子群組

預設情況下,當您將群組新增至此政策時,存取限制僅適用於選取群組的成員。

在某些情況下,可能需要允許不僅存取群組本身,還可以存取階層中的任何子群組。對於新增的任何群組,您可以勾選 延伸至子群組 核取方塊,以便將存取權延伸至子群組。

擴展子群組的存取權

Extending access to child groups

在上面的範例中,此政策會授予 IT 或其任何子群組的任何使用者成員存取權。

基於用戶端範圍的政策

您可以使用此類型的政策來定義權限的條件,其中一組或多個用戶端範圍被允許存取物件。

預設情況下,新增至此政策的用戶端範圍不會指定為必要,如果請求存取的用戶端已被授予任何這些用戶端範圍,則此政策會授予存取權。但是,如果您想要強制執行特定用戶端範圍,您可以將特定用戶端範圍指定為必要

若要建立新的基於用戶端範圍的政策,請從政策類型列表中選取 用戶端範圍

新增用戶端範圍政策

Add Client Scope Policy

設定

  • 名稱

    一個人類可讀且唯一描述策略的字串。最佳做法是使用與您的業務和安全需求密切相關的名稱,以便您可以更輕鬆地識別它們。

  • 描述

    一個包含有關此策略詳細資訊的字串。

  • 用戶端範圍

    指定此政策允許哪些用戶端範圍。

  • 邏輯

    此策略在評估其他條件後套用的邏輯。

其他資源

將用戶端範圍定義為必要

建立基於用戶端範圍的政策時,您可以將特定用戶端範圍指定為 必要。當您這樣做時,只有在請求存取的用戶端已被授予 所有 必要 用戶端範圍時,此政策才會授予存取權。

必要用戶端範圍的範例

Example of required client scope

若要將用戶端範圍指定為必要,請針對您想要設定為必要的用戶端範圍,選取 必要 核取方塊。

當您的政策定義了多個用戶端範圍,但其中只有一部分是強制性的時,必要的用戶端範圍會很有用。

基於 Regex 的政策

您可以使用此類型的政策來定義權限的 regex 條件。

若要建立新的基於 regex 的政策,請從政策類型列表中選取 Regex

此政策會解析目前身分可用的屬性。

新增 Regex 政策

Add Regex Policy

設定

  • 名稱

    一個人類可讀且唯一描述策略的字串。最佳做法是使用與您的業務和安全需求密切相關的名稱,以便您可以更輕鬆地識別它們。

  • 描述

    一個包含有關此策略詳細資訊的字串。

  • 目標聲明

    指定權杖中的目標聲明名稱。對於基於 JSON 的聲明,您可以使用點號表示法來進行巢狀結構,並使用方括號按索引存取陣列欄位。例如,contact.address[0].country。如果目標聲明參考 JSON 物件,則第一個路徑(例如,contact)應該對應到保存 JSON 物件的屬性名稱。

  • Regex 模式

    指定 regex 模式。

  • 邏輯

    在評估其他條件之後要套用的此政策的 邏輯

正向和反向邏輯

政策可以設定為正向或反向邏輯。簡而言之,您可以使用此選項來定義政策結果應該保持原狀還是被否定。

例如,假設您想要建立一個政策,其中只有 被授予特定角色的使用者才應被授予存取權。在這種情況下,您可以使用該角色建立一個基於角色的政策,並將其 邏輯 欄位設定為 反向。如果您保持 正向,這是預設行為,則政策結果將保持原狀。

政策評估 API

當使用 JavaScript 編寫基於規則的政策時,Keycloak 提供了一個評估 API,該 API 提供有用的資訊來協助判斷是否應授予權限。

此 API 由幾個介面組成,這些介面可讓您存取以下資訊,例如

  • 正在評估的權限,代表正在請求的資源和範圍。

  • 與正在請求的資源相關聯的屬性

  • 執行環境和與執行內容相關聯的任何其他屬性

  • 有關使用者的資訊,例如群組成員資格和角色

主要介面是 org.keycloak.authorization.policy.evaluation.Evaluation,它定義了以下合約

public interface Evaluation {

    /**
     * Returns the {@link ResourcePermission} to be evaluated.
     *
     * @return the permission to be evaluated
     */
    ResourcePermission getPermission();

    /**
     * Returns the {@link EvaluationContext}. Which provides access to the whole evaluation runtime context.
     *
     * @return the evaluation context
     */
    EvaluationContext getContext();

    /**
     * Returns a {@link Realm} that can be used by policies to query information.
     *
     * @return a {@link Realm} instance
     */
    Realm getRealm();

    /**
     * Grants the requested permission to the caller.
     */
    void grant();

    /**
     * Denies the requested permission.
     */
    void deny();
}

在處理授權請求時,Keycloak 會在評估任何政策之前建立 Evaluation 實例。然後將此實例傳遞給每個政策,以判斷存取是否為 GRANTDENY

政策會透過調用 Evaluation 實例上的 grant()deny() 方法來確定這一點。預設情況下,Evaluation 實例的狀態為已拒絕,這表示您的政策必須明確調用 grant() 方法,以向政策評估引擎指示應授予權限。

其他資源

評估內容

評估內容在政策評估期間向政策提供有用的資訊。

public interface EvaluationContext {

    /**
     * Returns the {@link Identity} that represents an entity (person or non-person) to which the permissions must be granted, or not.
     *
     * @return the identity to which the permissions must be granted, or not
     */
    Identity getIdentity();

    /**
     * Returns all attributes within the current execution and runtime environment.
     *
     * @return the attributes within the current execution and runtime environment
     */
    Attributes getAttributes();
}

從此介面中,政策可以取得

  • 已驗證的 Identity

  • 有關執行內容和執行環境的資訊

Identity 是根據隨授權請求一起傳送的 OAuth2 存取權杖建立的,此建構可以存取從原始權杖中提取的所有聲明。例如,如果您使用 *協定對應器* 在 OAuth2 存取權杖中包含自訂聲明,您也可以從政策存取此聲明,並使用它來建立您的條件。

EvaluationContext 也可讓您存取與執行和執行環境相關的屬性。目前,只有一些內建屬性。

表 1. 執行和執行環境屬性
名稱 描述 類型

kc.time.date_time

目前日期和時間

字串。格式 MM/dd/yyyy hh:mm:ss

kc.client.network.ip_address

用戶端的 IPv4 位址

字串

kc.client.network.host

用戶端的主機名稱

字串

kc.client.id

用戶端 ID

字串

kc.client.user_agent

「User-Agent」HTTP 標頭的值

字串[]

kc.realm.name

領域的名稱

字串

管理權限

權限將受保護的物件與必須評估的政策關聯起來,以決定是否應授予存取權。

在建立您想要保護的資源以及您想要用來保護這些資源的政策之後,您可以開始管理權限。若要管理權限,請在編輯資源伺服器時點擊 Permissions(權限) 標籤。

權限

Permissions

可以建立權限來保護兩種主要類型的物件

  • 資源

  • 範圍

若要建立權限,請從權限清單右上角的項目列表中選擇您想要建立的權限類型。以下章節將更詳細地描述這兩種物件類型。

建立基於資源的權限

基於資源的權限定義一組或多組資源,以使用一組或多組授權政策來保護。

若要建立新的基於資源的權限,請從 Create permission(建立權限) 下拉式選單中選擇 Create resource-based permission(建立基於資源的權限)

新增資源權限

Add Resource Permission

設定

  • 名稱

    一個人類可讀且獨特的字串,用於描述權限。最佳實務是使用與您的業務和安全需求密切相關的名稱,以便您更容易識別它們。

  • 描述

    一個包含此權限詳細資訊的字串。

  • 套用至資源類型

    指定是否將權限套用至具有指定類型的所有資源。當選擇此欄位時,系統會提示您輸入要保護的資源類型。

    • 資源類型

      定義要保護的資源類型。定義後,將會針對所有符合該類型的資源評估此權限。

  • 資源

    定義要保護的一組或多組資源。

  • 政策

    定義一組或多組要與權限關聯的政策。若要關聯政策,您可以選擇現有政策,或選擇您要建立的政策類型來建立新政策。

  • 決策策略

    此權限的決策策略

類型化資源權限

資源權限也可用於定義要套用至具有指定類型的所有資源的政策。當您的資源具有共同的存取需求和限制時,此種基於資源的權限會很有用。

通常,應用程式中的資源可以根據它們封裝的資料或它們提供的功能進行分類(或類型化)。例如,金融應用程式可以管理不同的銀行帳戶,而每個帳戶都屬於特定的客戶。儘管它們是不同的銀行帳戶,但它們具有由銀行組織統一定義的共同安全需求和限制。使用類型化資源權限,您可以定義套用至所有銀行帳戶的通用政策,例如

  • 只有擁有者才能管理他的帳戶

  • 僅允許從擁有者的國家和/或地區存取

  • 強制執行特定的驗證方法

若要建立類型化資源權限,請在建立新的基於資源的權限時,點擊套用至資源類型。在 Apply to Resource Type(套用至資源類型) 設定為 On(開啟) 時,您可以指定要保護的類型,以及要套用以管理對具有您指定類型之所有資源的存取的政策。

類型化資源權限範例

Example of a typed resource permission

建立基於範圍的權限

基於範圍的權限定義一組或多組範圍,以使用一組或多組授權政策來保護。與基於資源的權限不同,您可以使用此權限類型不僅為資源建立權限,還可以為與其關聯的範圍建立權限,從而在定義管理您的資源和可以在其上執行的動作的權限時提供更高的精細度。

若要建立新的基於範圍的權限,請從 Create permission(建立權限) 下拉式選單中選擇 Create scope-based permission(建立基於範圍的權限)

新增範圍權限

Add Scope Permission

設定

  • 名稱

    一個人類可讀且獨特的字串,用於描述權限。最佳實務是使用與您的業務和安全需求密切相關的名稱,以便您更容易識別它們。

  • 描述

    一個包含此權限詳細資訊的字串。

  • 資源

    將範圍限制為與所選資源關聯的範圍。如果未選擇任何資源,則所有範圍都可用。

  • 範圍

    定義一組或多組要保護的範圍。

  • 政策

    定義一組或多組要與權限關聯的政策。若要關聯政策,您可以選擇現有政策,或選擇您要建立的政策類型來建立新政策。

  • 決策策略

    此權限的決策策略

政策決策策略

將政策與權限關聯時,您還可以定義決策策略,以指定如何評估相關政策的結果來判斷存取權。

  • 一致同意

    如果未提供任何策略,則為預設策略。在這種情況下,所有政策都必須評估為正面決策,最終決策才會為正面。

  • 肯定

    在這種情況下,至少一個政策必須評估為肯定決策,最終決策才會是肯定決策。

  • 共識

    在這種情況下,肯定決策的數量必須大於否定決策的數量。如果肯定和否定決策的數量相等,則最終決策將為否定。

評估和測試政策

在設計政策時,您可以模擬授權請求來測試政策的評估方式。

您可以透過在編輯資源伺服器時點擊 Evaluate(評估) 標籤來存取政策評估工具。在那裡,您可以指定不同的輸入來模擬真實的授權請求,並測試政策的效果。

政策評估工具

Policy evaluation tool

提供身分資訊

Identity Information(身分資訊)篩選器可以用於指定請求權限的使用者。

提供上下文資訊

Contextual Information(上下文資訊)篩選器可以用於定義評估上下文的其他屬性,以便政策可以取得這些相同的屬性。

提供權限

Permissions(權限)篩選器可以用於建立授權請求。您可以為一組或多組資源和範圍請求權限。如果您想要模擬基於所有受保護資源和範圍的授權請求,請在不指定任何 Resources(資源)Scopes(範圍) 的情況下點擊 Add(新增)

在您指定所需的值後,點擊 Evaluate(評估)

授權服務

Keycloak 授權服務建立在眾所周知的標準之上,例如 OAuth2 和使用者管理的存取規範。

OAuth2 客戶端(例如前端應用程式)可以使用令牌端點從伺服器取得存取令牌,並使用這些令牌來存取受資源伺服器(例如後端服務)保護的資源。同樣地,Keycloak 授權服務提供了 OAuth2 的擴展功能,允許根據與所請求的資源或範圍相關聯的所有原則處理來發放存取令牌。這表示資源伺服器可以根據伺服器授予並由存取令牌持有的權限來強制存取其受保護的資源。在 Keycloak 授權服務中,具有權限的存取令牌稱為請求方令牌(Requesting Party Token),簡稱 RPT。

除了發行 RPT 之外,Keycloak 授權服務還提供一組 RESTful 端點,允許資源伺服器管理其受保護的資源、範圍、權限和政策,幫助開發人員將這些功能擴展或整合到其應用程式中,以支援精細的授權。

探索授權服務端點和中繼資料

Keycloak 提供了一個探索文件,客戶端可以從中取得與 Keycloak 授權服務互動所需的所有資訊,包括端點位置和功能。

可以從以下位置取得探索文件

curl -X GET \
  http://${host}:${port}/realms/${realm}/.well-known/uma2-configuration

其中 ${host}:${port} 是執行 Keycloak 的主機名稱(或 IP 位址)和連接埠,而 ${realm} 是 Keycloak 中網域的名稱。

結果,您應該得到如下回應

{

    // some claims are expected here

    // these are the main claims in the discovery document about Authorization Services endpoints location
    "token_endpoint": "http://${host}:${port}/realms/${realm}/protocol/openid-connect/token",
    "token_introspection_endpoint": "http://${host}:${port}/realms/${realm}/protocol/openid-connect/token/introspect",
    "resource_registration_endpoint": "http://${host}:${port}/realms/${realm}/authz/protection/resource_set",
    "permission_endpoint": "http://${host}:${port}/realms/${realm}/authz/protection/permission",
    "policy_endpoint": "http://${host}:${port}/realms/${realm}/authz/protection/uma-policy"
}

每個端點都公開一組特定的功能

  • token_endpoint

    一個符合 OAuth2 的權杖端點,支援 urn:ietf:params:oauth:grant-type:uma-ticket 授權類型。透過這個端點,客戶端可以傳送授權請求,並取得 Keycloak 授予的所有權限的 RPT。

  • token_introspection_endpoint

    一個符合 OAuth2 的權杖內省端點,客戶端可以使用它來查詢伺服器以判斷 RPT 的活動狀態,並判斷與權杖相關聯的任何其他資訊,例如 Keycloak 授予的權限。

  • resource_registration_endpoint

    一個符合 UMA 的資源註冊端點,資源伺服器可以使用它來管理其受保護的資源和範圍。此端點提供在 Keycloak 中建立、讀取、更新和刪除資源和範圍的操作。

  • permission_endpoint

    一個符合 UMA 的權限端點,資源伺服器可以使用它來管理權限票證。此端點提供在 Keycloak 中建立、讀取、更新和刪除權限票證的操作。

取得權限

要從 Keycloak 取得權限,您需要發送授權請求到令牌端點。結果,Keycloak 將評估與被請求的資源和範圍相關聯的所有政策,並發出一個 RPT,其中包含伺服器授予的所有權限。

客戶端可以使用以下參數發送授權請求到令牌端點

  • grant_type

    此參數為必填。必須為 urn:ietf:params:oauth:grant-type:uma-ticket

  • ticket

    此參數為選填。客戶端在 UMA 授權流程中收到的最新權限票證。

  • claim_token

    此參數為選填。一個字串,表示在評估被請求的資源和範圍的權限時,伺服器應考慮的其他聲明。此參數允許客戶端將聲明推送至 Keycloak。有關所有支援的令牌格式的更多詳細資訊,請參閱 claim_token_format 參數。

  • claim_token_format

    此參數為選填。一個字串,指示 claim_token 參數中指定的令牌格式。Keycloak 支援兩種令牌格式:urn:ietf:params:oauth:token-type:jwthttps://openid.net/specs/openid-connect-core-1_0.html#IDTokenurn:ietf:params:oauth:token-type:jwt 格式表示 claim_token 參數引用一個存取令牌。https://openid.net/specs/openid-connect-core-1_0.html#IDToken 表示 claim_token 參數引用一個 OpenID Connect ID 令牌。

  • rpt

    此參數為選填。先前發佈的 RPT,其權限也應評估並新增到新的 RPT 中。此參數允許持有 RPT 的客戶端執行增量授權,其中權限是按需新增的。

  • permission

    此參數為選填。一個字串,表示客戶端正在尋求存取的一組或多個資源和範圍。可以多次定義此參數,以便請求多個資源和範圍的權限。此參數是 urn:ietf:params:oauth:grant-type:uma-ticket 授權類型的擴充,允許客戶端在沒有權限票證的情況下發送授權請求。字串的格式必須為:RESOURCE_ID#SCOPE_ID。例如:Resource A#Scope AResource A#Scope A, Scope B, Scope CResource A#Scope A

  • permission_resource_format

    此參數為選填。一個字串,表示 permission 參數中資源的格式。可能的值為 iduriid 表示格式為 RESOURCE_IDuri 表示格式為 URI。如果未指定,則預設為 id

  • permission_resource_matching_uri

    此參數為選填。一個布林值,指示當在 permission 參數中使用 URI 格式表示資源時,是否使用路徑匹配。如果未指定,則預設為 false。

  • audience

    此參數為選填。客戶端正在尋求存取的資源伺服器的客戶端識別符。如果定義了 permission 參數,則此參數為強制性的。它作為 Keycloak 的提示,以指示應評估權限的上下文。

  • response_include_resource_name

    此參數為選填。一個布林值,向伺服器指示是否應在 RPT 的權限中包含資源名稱。如果為 false,則僅包含資源識別符。

  • response_permissions_limit

    此參數為選填。一個整數 N,定義一個 RPT 可以擁有的權限數量限制。當與 rpt 參數一起使用時,RPT 中僅保留最後 N 個請求的權限。

  • submit_request

    此參數為選填。一個布林值,指示伺服器是否應為權限票證引用的資源和範圍建立權限請求。此參數僅在與 ticket 參數一起作為 UMA 授權流程的一部分使用時才有效。

  • response_mode

    此參數為選填。一個字串值,指示伺服器應如何回應授權請求。當您主要對伺服器的整體決策或授予的權限感興趣,而不是標準的 OAuth2 回應時,此參數特別有用。可能的值為

    • decision

      表示伺服器的回應應僅表示整體決策,方法是傳回具有以下格式的 JSON

      {
          'result': true
      }

      如果授權請求未對應任何權限,則會改為傳回 403 HTTP 狀態代碼。

    • permissions

      表示伺服器的回應應包含伺服器授予的任何權限,方法是傳回具有以下格式的 JSON

      [
          {
              'rsid': 'My Resource'
              'scopes': ['view', 'update']
          },
      
          ...
      ]

      如果授權請求未對應任何權限,則會改為傳回 403 HTTP 狀態代碼。

當客戶端正在尋求存取受資源伺服器保護的兩個資源時,授權請求的範例。

curl -X POST \
  http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "audience={resource_server_client_id}" \
  --data "permission=Resource A#Scope A" \
  --data "permission=Resource B#Scope B"

當客戶端正在尋求存取受資源伺服器保護的任何資源和範圍時,授權請求的範例。注意:這不會評估所有資源的權限。相反,將評估資源伺服器擁有的資源、請求使用者擁有的資源以及其他擁有者明確授予請求使用者的資源的權限。

curl -X POST \
  http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "audience={resource_server_client_id}"

當客戶端在收到來自資源伺服器的權限票證作為授權流程的一部分後,正在尋求存取受 UMA 保護的資源時,授權請求的範例

curl -X POST \
  http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "ticket=${permission_ticket}

如果 Keycloak 評估流程導致權限發放,則會發放與權限相關聯的 RPT

Keycloak 使用 RPT 回應客戶端
HTTP/1.1 200 OK
Content-Type: application/json
...
{
    "access_token": "${rpt}",
}

伺服器的回應與使用其他授權類型時來自令牌端點的任何其他回應一樣。RPT 可以從 access_token 回應參數中取得。如果客戶端未獲得授權,Keycloak 會以 403 HTTP 狀態代碼回應

Keycloak 拒絕授權請求
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}

客戶端驗證方法

客戶端需要驗證令牌端點才能取得 RPT。使用 urn:ietf:params:oauth:grant-type:uma-ticket 授權類型時,客戶端可以使用以下任何一種驗證方法

  • 持有者令牌

    客戶端應在 HTTP Authorization 標頭中以持有者憑證的形式發送存取令牌到令牌端點。

    範例:使用存取令牌驗證令牌端點的授權請求
    curl -X POST \
      http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
      -H "Authorization: Bearer ${access_token}" \
      --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"

    當客戶端代表使用者執行動作時,此方法特別有用。在這種情況下,持有者令牌是 Keycloak 先前發給代表使用者(或代表自己)執行動作的某個客戶端的存取令牌。將考慮到由存取令牌代表的存取上下文來評估權限。例如,如果存取令牌發給了代表使用者 A 執行動作的客戶端 A,則將根據使用者 A 可以存取的資源和範圍來授予權限。

  • 客戶端憑證

    客戶端可以使用 Keycloak 支援的任何客戶端驗證方法。例如,client_id/client_secret 或 JWT。

    範例:使用客戶端 ID 和客戶端密碼驗證令牌端點的授權請求
    curl -X POST \
      http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
      -H "Authorization: Basic cGhvdGg6L7Jl13RmfWgtkk==pOnNlY3JldA==" \
      --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"

推送聲明

從伺服器取得權限時,您可以推送任意聲明,以便在評估權限時,您的策略可以使用這些聲明。

如果您沒有使用權限票證(UMA 流程)從伺服器取得權限,您可以按如下方式發送授權請求到令牌端點

curl -X POST \
  http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "claim_token=ewogICAib3JnYW5pemF0aW9uIjogWyJhY21lIl0KfQ==" \
  --data "claim_token_format=urn:ietf:params:oauth:token-type:jwt" \
  --data "client_id={resource_server_client_id}" \
  --data "client_secret={resource_server_client_secret}" \
  --data "audience={resource_server_client_id}"

claim_token 參數期望一個 BASE64 編碼的 JSON,其格式與下面的範例類似

{
    "organization" : ["acme"]
}

該格式期望一個或多個聲明,其中每個聲明的值必須是一個字串陣列。

使用 UMA 推送聲明

有關在使用 UMA 和權限票證時如何推送聲明的更多詳細資訊,請參閱權限 API

使用者管理的存取

Keycloak 授權服務基於使用者管理的存取或簡稱 UMA。UMA 是一個增強 OAuth2 功能的規範,它以以下方式執行

  • 隱私

    如今,隨著越來越多的資料和裝置可用並連接到雲端,使用者隱私正成為一個巨大的問題。透過 UMA 和 Keycloak,資源伺服器可以增強其功能,以提高在尊重使用者隱私的情況下保護其資源的方式,其中權限是根據使用者定義的策略授予的。

  • 對等方授權

    資源擁有者(例如:一般終端使用者)可以管理其資源的存取權,並授權其他方(例如:一般終端使用者)存取這些資源。這與 OAuth2 不同,在 OAuth2 中,授權是授予代表使用者操作的客戶端應用程式,而在 UMA 中,資源擁有者可以完全非同步地授權其他使用者存取。

  • 資源分享

    資源擁有者可以管理其資源的權限,並決定誰可以存取特定資源以及如何存取。Keycloak 可以作為一個分享管理服務,資源擁有者可以從該服務管理其資源。

Keycloak 是一個符合 UMA 2.0 規範的授權伺服器,提供大多數 UMA 功能。

舉例來說,假設使用者 Alice(資源擁有者)使用網路銀行服務(資源伺服器)來管理她的銀行帳戶(資源)。有一天,Alice 決定向會計專業人士 Bob(請求方)開放她的銀行帳戶。然而,Bob 應該只能存取檢視(範圍)Alice 的帳戶。

作為資源伺服器,網路銀行服務必須能夠保護 Alice 的銀行帳戶。為此,它依賴 Keycloak 資源註冊端點在伺服器中建立一個代表 Alice 銀行帳戶的資源。

此時,如果 Bob 試圖存取 Alice 的銀行帳戶,存取將被拒絕。網路銀行服務為銀行帳戶定義了一些預設原則。其中一項原則是,只有擁有者(在本例中為 Alice)才能存取她的銀行帳戶。

然而,為了尊重 Alice 的隱私,網路銀行服務也允許她更改銀行帳戶的特定原則。她可以更改的其中一項原則是定義哪些人可以檢視她的銀行帳戶。為此,網路銀行服務依賴 Keycloak 向 Alice 提供一個空間,讓她可以選擇個人以及他們被允許存取的操作(或資料)。Alice 可以隨時撤銷存取權或授予 Bob 額外的權限。

授權流程

在 UMA 中,當客戶端嘗試存取受 UMA 保護的資源伺服器時,授權流程開始。

受 UMA 保護的資源伺服器期望在請求中帶有持有者權杖,其中權杖是 RPT。當客戶端在沒有 RPT 的情況下請求資源伺服器上的資源時

客戶端請求受保護的資源,但未傳送 RPT
curl -X GET \
  http://${host}:${port}/my-resource-server/resource/1bfdfe78-a4e1-4c2d-b142-fc92b75b986f

資源伺服器會將包含許可憑證as_uri 參數的回應傳回客戶端,其中包含 Keycloak 伺服器的位置,該憑證應傳送到該伺服器以取得 RPT。

資源伺服器以許可憑證回應
HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm}",
    as_uri="https://${host}:${port}/realms/${realm}",
    ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"

許可憑證是 Keycloak 許可 API 發行的特殊類型權杖。它們代表所請求的權限(例如:資源和範圍)以及與請求相關聯的任何其他資訊。只有資源伺服器才能建立這些權杖。

現在,客戶端有了許可憑證和 Keycloak 伺服器的位置,客戶端可以使用探索文件來取得權杖端點的位置並傳送授權請求。

客戶端將授權請求傳送到權杖端點以取得 RPT
curl -X POST \
  http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "ticket=${permission_ticket}

如果 Keycloak 評估流程導致權限發放,則會發放與權限相關聯的 RPT

Keycloak 使用 RPT 回應客戶端
HTTP/1.1 200 OK
Content-Type: application/json
...
{
    "access_token": "${rpt}",
}

伺服器的回應與使用其他授權類型的權杖端點的回應相同。RPT 可以從 access_token 回應參數取得。如果客戶端未被授權擁有權限,Keycloak 會以 403 HTTP 狀態碼回應

Keycloak 拒絕授權請求
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}

提交許可請求

作為授權流程的一部分,客戶端需要先從受 UMA 保護的資源伺服器取得許可憑證,以便在 Keycloak 權杖端點將其交換為 RPT。

預設情況下,如果無法向客戶端發出 RPT,Keycloak 會以 403 HTTP 狀態碼和 request_denied 錯誤回應。

Keycloak 拒絕授權請求
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}

此類回應表示 Keycloak 無法發出具有許可憑證所代表權限的 RPT。

在某些情況下,客戶端應用程式可能希望啟動非同步授權流程,並讓所請求資源的擁有者決定是否應授予存取權。為此,客戶端可以使用 submit_request 請求參數以及傳送到權杖端點的授權請求

curl -X POST \
  http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "ticket=${permission_ticket} \
  --data "submit_request=true"

使用 submit_request 參數時,Keycloak 會為每個被拒絕存取的資源保留許可請求。建立完成後,資源擁有者可以查看其帳戶並管理其許可請求。

您可以將此功能視為應用程式中的「請求存取」按鈕,使用者可以在其中要求其他使用者存取其資源。

管理使用者資源的存取權

使用者可以使用 Keycloak 帳戶控制台管理其資源的存取權。若要啟用此功能,您必須先為您的領域啟用使用者管理存取權。

步驟
  1. 登入管理控制台。

  2. 在選單中按一下領域設定

  3. 使用者管理存取權切換為開啟

  4. 按一下管理控制台右上角的使用者名稱,然後選取管理帳戶

    My Resources

  5. 在選單選項中按一下我的資源。將顯示一個包含下列選項的頁面。

    • 管理我的資源

      本節包含使用者擁有的所有資源的清單。使用者可以按一下資源以取得更多詳細資訊並與他人分享資源。當有待核准的許可請求時,資源名稱旁邊會出現一個圖示。這些請求與請求存取特定資源的當事方(使用者)相關聯。使用者可以核准或拒絕這些請求。您可以按一下圖示來執行此操作

      Resource Detail

    • 管理與我分享的資源

      本節包含與使用者分享的所有資源的清單。

    • 管理可以存取此資源的人員

      本節包含可以存取此資源的人員的清單。使用者可以按一下「撤銷」按鈕或移除特定的「許可」來撤銷存取權。

    • 與他人分享資源

      透過輸入其他使用者的使用者名稱或電子郵件,使用者可以分享資源並選取他想授予存取權的權限。

保護 API

保護 API 提供一組符合 UMA 規範的端點,可提供

  • 資源管理

    透過此端點,資源伺服器可以遠端管理其資源,並啟用原則執行器,以查詢伺服器中需要保護的資源。

  • 權限管理

    在 UMA 通訊協定中,資源伺服器會存取此端點以建立許可憑證。Keycloak 也提供端點來管理權限的狀態和查詢權限。

  • 原則 API

    Keycloak 利用 UMA 保護 API,允許資源伺服器管理其使用者的權限。除了資源和許可 API 之外,Keycloak 還提供原則 API,資源伺服器可以從該 API 代表其使用者設定資源的權限。

此 API 的一個重要要求是,只有資源伺服器才能使用稱為保護 API 權杖 (PAT) 的特殊 OAuth2 存取權杖來存取其端點。在 UMA 中,PAT 是範圍為 uma_protection 的權杖。

什麼是 PAT 以及如何取得 PAT

保護 API 權杖 (PAT) 是一個特殊的 OAuth2 存取權杖,其範圍定義為 uma_protection。當您建立資源伺服器時,Keycloak 會自動為對應的客戶端應用程式建立一個角色 uma_protection,並將其與客戶端的服務帳戶相關聯。

已授予 uma_protection 角色的服務帳戶

Service Account granted with uma_protection role

資源伺服器可以像任何其他 OAuth2 存取權杖一樣從 Keycloak 取得 PAT。例如,使用 curl

curl -X POST \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d 'grant_type=client_credentials&client_id=${client_id}&client_secret=${client_secret}' \
    "http://${host}:${port}/realms/${realm_name}/protocol/openid-connect/token"

上面的範例使用 client_credentials 授權類型從伺服器取得 PAT。因此,伺服器會傳回類似下列的回應

{
  "access_token": ${PAT},
  "expires_in": 300,
  "refresh_expires_in": 1800,
  "refresh_token": ${refresh_token},
  "token_type": "bearer",
  "id_token": ${id_token},
  "not-before-policy": 0,
  "session_state": "ccea4a55-9aec-4024-b11c-44f6f168439e"
}
Keycloak 可以透過不同的方式驗證您的客戶端應用程式。為了簡單起見,這裡使用了 client_credentials 授權類型,這需要 client_idclient_secret。您可以選擇使用任何支援的驗證方法。

管理資源

資源伺服器可以使用符合 UMA 規範的端點遠端管理其資源。

http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set

此端點提供以下概述的操作(為清楚起見,省略了整個路徑)

  • 建立資源集描述:POST /resource_set

  • 讀取資源集描述:GET /resource_set/{_id}

  • 更新資源集描述:PUT /resource_set/{_id}

  • 刪除資源集描述:DELETE /resource_set/{_id}

  • 列出資源集描述:GET /resource_set

如需有關每個操作合約的詳細資訊,請參閱UMA 資源註冊 API

建立資源

若要建立資源,您必須傳送如下所示的 HTTP POST 請求

curl -v -X POST \
  http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Tweedl Social Service",
     "type":"http://www.example.com/rsrcs/socialstream/140-compatible",
     "icon_uri":"http://www.example.com/icons/sharesocial.png",
     "resource_scopes":[
         "read-public",
         "post-updates",
         "read-private",
         "http://www.example.com/scopes/all"
      ]
  }'

預設情況下,資源的擁有者是資源伺服器。如果您想定義不同的擁有者,例如特定使用者,您可以傳送如下所示的請求

curl -v -X POST \
  http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Alice Resource",
     "owner": "alice"
  }'

屬性 owner 可以設定為使用者名稱或使用者識別碼。

建立使用者管理的資源

預設情況下,透過 Protection API 建立的資源無法由資源擁有者透過帳戶控制台進行管理。

若要建立資源並允許資源擁有者管理這些資源,您必須將 ownerManagedAccess 屬性設定如下

curl -v -X POST \
  http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Alice Resource",
     "owner": "alice",
     "ownerManagedAccess": true
  }'
更新資源

若要更新現有資源,請發送如下的 HTTP PUT 請求

curl -v -X PUT \
  http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set/{resource_id} \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "_id": "Alice Resource",
     "name":"Alice Resource",
     "resource_scopes": [
        "read"
     ]
  }'
刪除資源

若要刪除現有資源,請發送如下的 HTTP DELETE 請求

curl -v -X DELETE \
  http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set/{resource_id} \
  -H 'Authorization: Bearer '$pat
查詢資源

若要依 id 查詢資源,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set/{resource_id}

若要依 name 查詢資源,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set?name=Alice Resource

預設情況下,name 篩選器將比對符合指定模式的任何資源。若要限制查詢只傳回完全符合的資源,請使用

http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set?name=Alice Resource&exactName=true

若要依 uri 查詢資源,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set?uri=/api/alice

若要依 owner 查詢資源,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set?owner=alice

若要依 type 查詢資源,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set?type=albums

若要依 scope 查詢資源,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm_name}/authz/protection/resource_set?scope=read

當向伺服器查詢權限時,請使用 firstmax 結果參數來限制結果。

管理權限請求

使用 UMA 通訊協定的資源伺服器可以使用特定端點來管理權限請求。此端點提供符合 UMA 標準的流程,用於註冊權限請求並取得權限票證。

http://${host}:${port}/realms/${realm_name}/authz/protection/permission

權限票證是一種特殊的安全令牌類型,代表權限請求。根據 UMA 規範,權限票證是

一種關聯處理程序,從授權伺服器傳遞到資源伺服器,從資源伺服器傳遞到用戶端,最終從用戶端傳遞回授權伺服器,以便授權伺服器評估要套用於授權資料請求的正確策略。

在大多數情況下,您不需要直接處理此端點。Keycloak 提供原則執行器,為您的資源伺服器啟用 UMA,以便它可以從授權伺服器取得權限票證,將此票證傳回用戶端應用程式,並根據最終請求方令牌 (RPT) 強制執行授權決策。

從 Keycloak 取得權限票證的過程由資源伺服器執行,而不是由一般用戶端應用程式執行,當用戶端嘗試存取受保護的資源但沒有必要的授權來存取資源時,會取得權限票證。發出權限票證是使用 UMA 時的重要環節,因為它允許資源伺服器

  • 從用戶端抽象化與資源伺服器保護的資源相關的資料

  • 在 Keycloak 中註冊授權請求,這些請求稍後可用於工作流程中,以根據資源擁有者的同意授予存取權

  • 將資源伺服器與授權伺服器分離,並允許它們使用不同的授權伺服器來保護和管理其資源

在用戶端方面,權限票證也有一些值得強調的重要方面

  • 用戶端不需要知道授權資料如何與受保護的資源相關聯。權限票證對用戶端完全不透明。

  • 用戶端可以存取不同資源伺服器上的資源,並受到不同授權伺服器的保護

這些只是 UMA 帶來的一些好處,UMA 的其他方面主要基於權限票證,特別是在隱私和使用者控制對其資源的存取方面。

建立權限票證

若要建立權限票證,請發送如下的 HTTP POST 請求

curl -X POST \
  http://${host}:${port}/realms/${realm_name}/authz/protection/permission \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '[
  {
    "resource_id": "{resource_id}",
    "resource_scopes": [
      "view"
    ]
  }
]'

建立票證時,您還可以推送任意宣告,並將這些宣告與票證關聯

curl -X POST \
  http://${host}:${port}/realms/${realm_name}/authz/protection/permission \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '[
  {
    "resource_id": "{resource_id}",
    "resource_scopes": [
      "view"
    ],
    "claims": {
        "organization": ["acme"]
    }
  }
]'

這些宣告將在評估與權限票證關聯的資源和範圍的權限時提供給您的原則。

其他不符合 UMA 標準的端點
建立權限票證

若要將 id 為 {resource_id} 的特定資源的權限授予 id 為 {user_id} 的使用者,作為資源擁有者,請發送如下的 HTTP POST 請求

curl -X POST \
     http://${host}:${port}/realms/${realm_name}/authz/protection/permission/ticket \
     -H 'Authorization: Bearer '$access_token \
     -H 'Content-Type: application/json' \
     -d '{
       "resource": "{resource_id}",
       "requester": "{user_id}",
       "granted": true,
       "scopeName": "view"
     }'
取得權限票證
curl http://${host}:${port}/realms/${realm_name}/authz/protection/permission/ticket \
     -H 'Authorization: Bearer '$access_token

您可以使用下列任何查詢參數

  • scopeId

  • resourceId

  • owner

  • requester

  • granted

  • returnNames

  • first

  • max

更新權限票證
curl -X PUT \
     http://${host}:${port}/realms/${realm_name}/authz/protection/permission/ticket \
     -H 'Authorization: Bearer '$access_token \
     -H 'Content-Type: application/json' \
     -d '{
       "id": "{ticket_id}"
       "resource": "{resource_id}",
       "requester": "{user_id}",
       "granted": false,
       "scopeName": "view"
     }'
刪除權限票證
curl -X DELETE http://${host}:${port}/realms/${realm_name}/authz/protection/permission/ticket/{ticket_id} \
     -H 'Authorization: Bearer '$access_token

使用原則 API 管理資源權限

Keycloak 利用 UMA 保護 API,允許資源伺服器管理其使用者的權限。除了資源和許可 API 之外,Keycloak 還提供原則 API,資源伺服器可以從該 API 代表其使用者設定資源的權限。

原則 API 位於

http://${host}:${port}/realms/${realm_name}/authz/protection/uma-policy/{resource_id}

此 API 受限於持票者令牌保護,該令牌必須表示使用者已授予資源伺服器代表其管理權限的同意。持票者令牌可以是從令牌端點使用以下方式取得的正規存取令牌

  • 資源擁有者密碼憑證授權類型

  • 令牌交換,為了將授予某些用戶端(公用用戶端)的存取令牌交換為以資源伺服器為對象的令牌

將權限與資源關聯

若要將權限與特定資源關聯,您必須發送如下的 HTTP POST 請求

curl -X POST \
  https://127.0.0.1:8180/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "roles": ["people-manager"]
}'

在上面的範例中,我們正在建立新權限並將其與由 resource_id 代表的資源關聯,其中具有 people-manager 角色的任何使用者都應被授予 read 範圍。

您也可以使用其他存取控制機制建立原則,例如使用群組

curl -X POST \
  https://127.0.0.1:8180/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "groups": ["/Managers/People Managers"]
}'

或特定的用戶端

curl -X POST \
  https://127.0.0.1:8180/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "clients": ["my-client"]
}'

甚至可以使用 JavaScript 使用自訂原則

curl -X POST \
  https://127.0.0.1:8180/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "condition": "my-deployed-script.js"
}'

也可以設定這些存取控制機制的任何組合。

若要更新現有權限,請發送如下的 HTTP PUT 請求

curl -X PUT \
  https://127.0.0.1:8180/realms/photoz/authz/protection/uma-policy/{permission_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "21eb3fed-02d7-4b5a-9102-29f3f09b6de2",
    "name": "Any people manager",
    "description": "Allow access to any people manager",
    "type": "uma",
    "scopes": [
        "album:view"
    ],
    "logic": "POSITIVE",
    "decisionStrategy": "UNANIMOUS",
    "owner": "7e22131a-aa57-4f5f-b1db-6e82babcd322",
    "roles": [
        "user"
    ]
}'
移除權限

若要移除與資源關聯的權限,請發送如下的 HTTP DELETE 請求

curl -X DELETE \
  https://127.0.0.1:8180/realms/photoz/authz/protection/uma-policy/{permission_id} \
  -H 'Authorization: Bearer '$access_token
查詢權限

若要查詢與資源關聯的權限,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm}/authz/protection/uma-policy?resource={resource_id}

若要依名稱查詢權限,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm}/authz/protection/uma-policy?name=Any people manager

若要查詢與特定範圍關聯的權限,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm}/authz/protection/uma-policy?scope=read

若要查詢所有權限,請發送如下的 HTTP GET 請求

http://${host}:${port}/realms/${realm}/authz/protection/uma-policy

當向伺服器查詢權限時,請使用 firstmax 結果參數來限制結果。

請求方令牌

請求方令牌 (RPT) 是使用JSON Web 簽章 (JWS)數位簽名的JSON Web 令牌 (JWT)。該令牌是基於 Keycloak 先前向代表使用者或代表自己行事的特定用戶端發出的 OAuth2 存取令牌建立的。

當您解碼 RPT 時,會看到類似以下的酬載

{
  "authorization": {
      "permissions": [
        {
          "resource_set_id": "d2fe9843-6462-4bfc-baba-b5787bb6e0e7",
          "resource_set_name": "Hello World Resource"
        }
      ]
  },
  "jti": "d6109a09-78fd-4998-bf89-95730dfd0892-1464906679405",
  "exp": 1464906971,
  "nbf": 0,
  "iat": 1464906671,
  "sub": "f1888f4d-5172-4359-be0c-af338505d86c",
  "typ": "kc_ett",
  "azp": "hello-world-authz-service"
}

從此令牌中,您可以從 permissions 宣告中取得伺服器授予的所有權限。

另請注意,權限與您正在保護的資源/範圍直接相關,並且與實際用於授予和發出這些相同權限的存取控制方法完全分離。

檢查請求方令牌

有時您可能想要檢查請求方令牌 (RPT),以檢查其有效性或取得令牌內的權限,以便在資源伺服器端強制執行授權決策。

令牌檢查可以幫助您解決兩個主要用例

  • 當用戶端應用程式需要查詢令牌有效性以取得具有相同或額外權限的新令牌時

  • 當在資源伺服器端強制執行授權決策時,特別是在沒有任何內建原則執行器適合您的應用程式時

取得有關 RPT 的資訊

令牌檢查本質上是符合OAuth2 令牌檢查的端點,您可以從該端點取得有關 RPT 的資訊。

http://${host}:${port}/realms/${realm_name}/protocol/openid-connect/token/introspect

若要使用此端點檢查 RPT,您可以向伺服器發送如下的請求

curl -X POST \
    -H "Authorization: Basic aGVsbG8td29ybGQtYXV0aHotc2VydmljZTpzZWNyZXQ=" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d 'token_type_hint=requesting_party_token&token=${RPT}' \
    "https://127.0.0.1:8080/realms/hello-world-authz/protocol/openid-connect/token/introspect"
上面的請求正在使用 HTTP BASIC 並傳遞用戶端的憑證(用戶端 ID 和密碼)來驗證嘗試檢查令牌的用戶端,但您可以使用 Keycloak 支援的任何其他用戶端驗證方法。

檢查端點需要兩個參數

  • token_type_hint

    requesting_party_token 作為此參數的值,這表示您想要檢查 RPT。

  • token

    使用授權過程中伺服器傳回的令牌字串作為此參數的值。

因此,伺服器回應是

{
  "permissions": [
    {
      "resource_id": "90ccc6fc-b296-4cd1-881e-089e1ee15957",
      "resource_name": "Hello World Resource"
    }
  ],
  "exp": 1465314139,
  "nbf": 0,
  "iat": 1465313839,
  "aud": "hello-world-authz-service",
  "active": true
}

如果 RPT 未啟用,則會傳回此回應

{
  "active": false
}

我是否每次想要內省 RPT 都需要調用伺服器?

不需要。就像 Keycloak 伺服器發出的常規存取令牌一樣,RPT 也使用 JSON Web Token (JWT) 規範作為預設格式。

如果您想要在不呼叫遠端內省端點的情況下驗證這些令牌,您可以解碼 RPT 並在本地查詢其有效性。一旦您解碼了令牌,您還可以利用令牌內的權限來執行授權決策。

這基本上就是政策執行器所做的事情。請務必

  • 驗證 RPT 的簽名(基於領域的公鑰)

  • 根據其 expiataud 宣告查詢令牌的有效性

其他資源

政策執行器概觀

政策執行點 (Policy Enforcement Point, PEP) 是一種設計模式,因此您可以用不同的方式實作它。Keycloak 提供了所有必要的手段來為不同的平台、環境和程式語言實作 PEP。Keycloak 授權服務提供 RESTful API,並利用 OAuth2 授權功能,使用集中式授權伺服器進行細粒度授權。

Keycloak 提供的政策執行器有

政策執行器的 JavaScript 整合

Keycloak 伺服器附帶一個 JavaScript 程式庫,您可以使用它與受政策執行器保護的資源伺服器互動。此程式庫基於 Keycloak JavaScript 轉接器,可以整合以允許您的客戶端從 Keycloak 伺服器取得權限。

您可以從 NPM 安裝此程式庫來取得它

npm install keycloak-js

接下來,您可以如下建立一個 KeycloakAuthorization 實例

import Keycloak from "keycloak-js";
import KeycloakAuthorization from "keycloak-js/authz";

const keycloak = new Keycloak({
    url: "http://keycloak-server",
    realm: "my-realm",
    clientId: "my-app"
});

const authorization = new KeycloakAuthorization(keycloak);

await keycloak.init();

// Now you can use the authorization object to interact with the server.

keycloak-js/authz 程式庫提供兩個主要功能

  • 如果您正在存取受 UMA 保護的資源伺服器,則可以使用權限票證從伺服器取得權限。

  • 通過發送應用程式想要存取的資源和範圍,從伺服器取得權限。

在這兩種情況下,該程式庫都允許您輕鬆地與資源伺服器和 Keycloak 授權服務互動,以取得帶有權限的令牌,您的客戶端可以使用這些令牌作為持有者令牌來存取資源伺服器上的受保護資源。

處理來自受 UMA 保護的資源伺服器的授權回應

如果資源伺服器受到政策執行器的保護,它會根據持有者令牌所攜帶的權限來回應客戶端請求。通常,當您嘗試使用缺乏存取受保護資源權限的持有者令牌存取資源伺服器時,資源伺服器會以 401 狀態碼和 WWW-Authenticate 標頭回應。

HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm}",
    as_uri="https://${host}:${port}/realms/${realm}",
    ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"

有關更多資訊,請參閱 UMA 授權流程

您的客戶端需要做的是從資源伺服器返回的 WWW-Authenticate 標頭中提取權限票證,並使用程式庫發送授權請求,如下所示

// prepare a authorization request with the permission ticket
const authorizationRequest = { ticket };

// send the authorization request, if successful retry the request
authorization.authorize(authorizationRequest).then((rpt) => {
    // onGrant
}, () => {
    // onDeny
}, () => {
    // onError
});

authorize 函數是完全非同步的,並支援一些回調函數來接收來自伺服器的通知

  • onGrant:函數的第一個參數。如果授權成功且伺服器返回帶有所請求權限的 RPT,則回調會接收 RPT。

  • onDeny:函數的第二個參數。僅在伺服器拒絕授權請求時呼叫。

  • onError:函數的第三個參數。僅在伺服器意外回應時呼叫。

大多數應用程式應使用 onGrant 回調在 401 回應後重試請求。後續請求應包含 RPT 作為重試的持有者令牌。

取得授權

keycloak-js/authz 程式庫提供了一個 entitlement 函數,您可以使用它通過提供客戶端想要存取的資源和範圍,從伺服器取得 RPT。

關於如何取得用戶可以存取的所有資源和範圍的權限的 RPT 的範例
authorization.entitlement("my-resource-server-id").then((rpt) => {
    // onGrant callback function.
    // If authorization was successful you'll receive an RPT
    // with the necessary permissions to access the resource server
});
關於如何取得特定資源和範圍權限的 RPT 的範例
authorization.entitlement("my-resource-server", {
    permissions: [
        {
            id: "Some Resource"
        }
    ]
}).then((rpt) => {
    // onGrant
});

當使用 entitlement 函數時,您必須提供您想要存取的資源伺服器的 client_id

entitlement 函數是完全非同步的,並支援一些回調函數來接收來自伺服器的通知

  • onGrant:函數的第一個參數。如果授權成功且伺服器返回帶有所請求權限的 RPT,則回調會接收 RPT。

  • onDeny:函數的第二個參數。僅在伺服器拒絕授權請求時呼叫。

  • onError:函數的第三個參數。僅在伺服器意外回應時呼叫。

授權請求

authorizeentitlement 函數都接受一個授權請求物件。可以使用以下屬性設定此物件

  • permissions

    一個表示資源和範圍的物件陣列。例如

    const authorizationRequest = {
       permissions: [
           {
               id: "Some Resource",
               scopes: ["view", "edit"]
           }
       ]
    }
  • metadata

    一個物件,其屬性定義伺服器應如何處理授權請求。

    • response_include_resource_name

      一個布林值,指示伺服器是否應在 RPT 的權限中包含資源名稱。如果為 false,則僅包含資源識別碼。

    • response_permissions_limit

      一個整數 N,定義 RPT 可以擁有的權限量的限制。與 rpt 參數一起使用時,RPT 中將僅保留最後 N 個請求的權限

  • submit_request

    一個布林值,指示伺服器是否應建立對權限票證引用的資源和範圍的權限請求。此參數僅在與 ticket 參數一起使用作為 UMA 授權流程的一部分時才會生效。

取得 RPT

如果您已經使用程式庫提供的任何授權函數取得了 RPT,您可以始終從授權物件取得 RPT,如下所示(假設它已通過前面顯示的技術之一初始化)

const rpt = authorization.rpt;