使用角色和角色宣告保護 Java Spring Boot 應用程式

本文示範一個 Java Spring Boot Web 應用程式,該應用程式使用 適用於 Java 的 Microsoft Entra ID Spring Boot Starter 用戶端程式庫 進行驗證、授權和權杖取得。 應用程式會使用 OpenID Connect 通訊協定讓使用者登入,並使用 Microsoft Entra ID Application Roles (app roles) 進行授權,以限制對某些路由的存取權。

應用程式角色以及安全組是實作授權的熱門方法。 您可以使用角色型訪問控制 (RBAC) 搭配應用程式角色和角色宣告,以最少的努力安全地強制執行授權原則。 另一種方法是使用 Microsoft Entra ID 群組和群組宣告。 Microsoft Entra 標識符群組和應用程式角色並非互斥。 您可以同時使用兩者來提供細微的存取控制。

如需涵蓋類似情境的影片,請參閱 在您的應用程式中使用應用程式角色、安全性群組、範圍和目錄角色實作授權。

如需進一步了解通訊協定在此案例及其他案例中的運作方式,請參閱 驗證與授權。

下圖顯示應用程式的拓撲:

顯示應用程式拓撲的圖表。

應用程式會使用適用於 Java 的 Microsoft Entra ID Spring Boot Starter 用戶端程式庫來讓使用者登入,並從 Microsoft Entra ID 取得ID 權杖。 ID 權杖包含角色聲明。 應用程式會檢查此宣告的值,以判斷用戶有權存取的頁面。

這種授權是使用 RBAC 實作。 使用 RBAC 時,系統管理員會將許可權授與角色,而不是授與個別使用者或群組的許可權。 系統管理員接著可以將角色指派給不同的使用者和群組,以控制誰可以存取特定內容和功能。

這個範例應用程式會定義下列兩個應用程式角色:

  • :已獲授權可存取 僅限管理員 和 一般使用者 頁面。
  • :已獲授權存取 一般使用者 頁面。

這些應用程式角色定義在應用程式的註冊資訊清單中,而該資訊清單位於 Azure 入口網站。 當使用者登入應用程式時,Microsoft Entra ID 會針對以角色成員資格形式個別授與給使用者的每個角色發出角色宣告。

您可以透過 Azure 入口網站 將使用者和群組指派給角色。

注意

如果使用 端點作為登入使用者時的授權端點,則租用戶中的來賓使用者不會有角色宣告。 您需要讓使用者登入特定租用戶端點,例如 。

必要條件

  • JDK 15 版。 此範例是在 Java 15 的系統上開發,但可能與其他版本相容。
  • Maven 3
  • 建議使用 適用於 Visual Studio Code 的 Java 擴充功能套件,在 Visual Studio Code 中執行此範例。
  • Microsoft Entra ID 租用戶。 如需更多資訊,請參閱 如何取得 Microsoft Entra ID 租用戶。
  • 您Microsoft Entra ID 租使用者中的用戶帳戶。 此範例不適用於個人Microsoft帳戶。 因此,如果您使用個人帳戶登入 Azure 入口網站,而且您的目錄中沒有使用者帳戶,您現在需要立即建立一個。
  • Visual Studio Code
  • 適用於 Visual Studio Code 的 Azure 工具

建議

  • 稍微熟悉 Spring Framework。
  • 對 Linux/OSX 終端機操作有基本了解。
  • jwt.ms 用於檢查您的權杖。
  • Fiddler 用於監控您的網路活動及進行疑難排解。
  • 關注 Microsoft Entra 部落格,隨時掌握最新發展。

設定範例

下列各節說明如何設定範例應用程式。

複製或下載範例存放庫

若要複製範例,請開啟Bash視窗,並使用下列命令:

git clone https://github.com/Azure-Samples/ms-identity-msal-java-samples.git
cd 4-spring-web-app/3-Authorization-II/roles

或者,瀏覽至 ms-identity-msal-java-samples 存放庫,然後將其下載為 .zip 檔案,並解壓縮到您的硬碟。

重要

若要避免 Windows 上的檔案路徑長度限制,請將存放庫複製到硬碟根目錄附近的目錄中。

在 Microsoft Entra ID 租用戶中註冊範例應用程式

此範例中有一個專案。 下列各節說明如何使用 Azure 入口網站 註冊應用程式。

選擇您要在其中建立應用程式的 Microsoft Entra ID 租用戶

若要選擇您的租使用者,請使用下列步驟:

  1. 登入 Azure 入口網站。

  2. 如果您的帳戶存在於一個以上的 Microsoft Entra ID 租用戶中,請在 Azure 入口網站右上角選取您的個人檔案,然後選取 切換目錄,將您的工作階段切換至所需的 Microsoft Entra ID 租用戶。

註冊應用程式(java-spring-webapp-roles)

若要註冊應用程式,請使用下列步驟:

  1. 前往Azure 入口網站,然後選取Microsoft Entra ID。

  2. 在瀏覽窗格中選取 [應用程式註冊 ],然後選取 [ 新增註冊]。

  3. 在出現的 [ 註冊應用程式] 頁面中 ,輸入下列應用程式註冊資訊:

    • 在 名稱 區段中,輸入有意義的應用程式名稱,供應用程式使用者查看,例如 。
    • 在 [支援的帳戶類型] 底下,選取 [僅在此組織目錄中的帳戶]。
    • 在 重新導向 URI (選用) 區段中,於下拉式方塊中選取 Web,然後輸入下列重新導向 URI:。
  4. 選取 註冊 以建立應用程式。

  5. 在應用程式的註冊頁面上,尋找並複製 應用程式 (用戶端) 識別碼 值,以供稍後使用。 您會在應用程式的組態檔或檔案中使用此值。

  6. 在應用程式的註冊頁面上,選取 瀏覽窗格中的 [憑證和秘密 ],以開啟您可以產生秘密並上傳憑證的頁面。

  7. 在用戶端密碼區段底下,選取新增用戶端密碼。

  8. 輸入描述 - 例如, 應用程式秘密。

  9. 選取祕密的到期日,或指定自訂存留期。 用戶端機密的有效期限限制為 24 個月,Microsoft 建議有效期少於 12 個月。 對於生產應用程式,建議使用憑證或聯邦身份憑證,而非用戶端秘密。

  10. 選取新增。 產生的值隨即顯示。

  11. 複製並儲存產生的值,以供後續步驟使用。 您需要此值用於您的程式碼設定檔。 此值不會再次顯示,而且您無法透過任何其他方式加以擷取。 因此,請務必先在 Azure 入口網站中將其儲存,再切換到任何其他畫面或窗格。

定義應用程式角色

若要定義應用程式角色,請使用下列步驟:

  1. 在同一個應用程式註冊中,於導覽窗格選取 應用程式角色。

  2. 選取 [ 建立應用程式角色],然後輸入下列值:

    • 針對 [ 顯示名稱],輸入適當的名稱,例如 PrivilegedAdmin。
    • 針對 [ 允許的成員類型],選擇 [ 使用者]。
    • 在值中輸入PrivilegedAdmin。
    • 在 Description 中,輸入 可檢視管理頁面的 PrivilegedAdmins。
  3. 選取 [ 建立應用程式角色],然後輸入下列值:

    • 針對 [ 顯示名稱],輸入適當的名稱,例如 RegularUser。
    • 針對 [ 允許的成員類型],選擇 [ 使用者]。
    • 在 值 中,輸入 RegularUser。
    • 在描述中,輸入可檢視使用者頁面的 RegularUsers。
  4. 選取 [套用] 以儲存變更。

將使用者指派給應用程式角色

若要將使用者新增至稍早定義的應用程式角色,請參閱這裡的指引:將使用者和群組指派給角色。


設定應用程式 (java-spring-webapp-roles) 以使用您的應用程式註冊

使用下列步驟來設定應用程式:

注意

在以下步驟中, 與 或 相同。

  1. 在 IDE 中開啟專案。

  2. 開啟 src\main\resources\application.yml 檔案。

  3. 找出預留位置 ,並將現有的值替換為您的 Microsoft Entra 租用戶識別碼。

  4. 找出預留位置 ,並將現有的值替換為從 Azure 入口網站複製的 應用程式的應用程式 ID 或 。

  5. 找出預留位置 ,並將現有值替換為您在建立 時從 Azure 入口網站複製並儲存的值。

  6. 開啟 src/main/java/com/microsoft/azuresamples/msal4j/msidentityspringbootapplication/Sample.Controller.java 檔案。

  7. 在此檔案中找出對 和 應用程式角色的參考。 如有必要,請變更它們以反映您在先前步驟中選擇的應用程式角色名稱。

執行範例

  • 部署至 Azure 容器應用程式
  • 在本機執行

下列各節說明如何將範例部署至 Azure 容器應用程式。

必要條件

  • Azure 帳戶。 如果您還沒有帳戶,請建立免費帳戶。 您需要 Azure 訂用帳戶的 Contributor 或 Owner 許可權,才能繼續進行。 如需更多資訊,請參閱 使用 Azure 入口網站指派 Azure 角色。
  • Azure CLI。
  • Azure 容器應用程式 CLI 擴充功能,版本為 或更新版本。 若要安裝最新版本,請使用 命令。
  • Java Development Kit 17 或更新版本。
  • Maven.

準備 Spring 專案

使用下列步驟來準備專案:

  1. 使用下列 Maven 命令來建置專案:

    mvn clean verify
    
  2. 使用下列命令在本機執行範例專案:

    mvn spring-boot:run
    

設定

若要從 CLI 登入 Azure,請執行下列命令並遵循提示來完成驗證流程。

az login

若要確定您執行的是最新版本 CLI,請執行升級命令。

az upgrade

接下來,安裝或更新 CLI 的 Azure 容器應用程式延伸模組。

如果您在 Azure CLI 中執行 命令時收到缺少參數的錯誤,請確定您已安裝最新版的 Azure 容器應用程式 擴充功能。

az extension add --name containerapp --upgrade

注意

從 2024 年 5 月開始,Azure CLI 延伸模組預設不會再啟用預覽功能。 若要存取 Container Apps 的預覽功能,請使用安裝 Container Apps 擴充功能。

az extension add --name containerapp --upgrade --allow-preview true

現在已安裝目前的擴充功能或模組,請註冊 和 命名空間。

注意

Azure 容器應用程式資源已從 命名空間移轉到 命名空間。 如需詳細資訊,請參閱 2022 年 3 月從 Microsoft.Web 移轉至 Microsoft.App 的命名空間移轉。

az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights

建立 Azure 容器應用程式 環境

現在您的 Azure CLI 設定已完成,接下來您可以定義本文中使用的環境變數了。

在您的 bash shell 中定義下列變數。

export RESOURCE_GROUP="ms-identity-containerapps"
export LOCATION="canadacentral"
export ENVIRONMENT="env-ms-identity-containerapps"
export API_NAME="ms-identity-api"
export JAR_FILE_PATH_AND_NAME="./target/ms-identity-spring-boot-webapp-0.0.1-SNAPSHOT.jar"

建立資源群組。

az group create  \
    --name $RESOURCE_GROUP \
    --location $LOCATION \

使用自動產生的Log Analytics工作區建立環境。

az containerapp env create \
    --name $ENVIRONMENT \
    --resource-group $RESOURCE_GROUP \
    --location $LOCATION

顯示容器應用程式環境的預設網域。 記下此網域以供稍後章節使用。

az containerapp env show \
    --name $ENVIRONMENT \
    --resource-group $RESOURCE_GROUP \
    --query properties.defaultDomain

準備應用程式以進行部署

當您將應用程式部署至 Azure 容器應用程式 時,您的重新導向 URL 會變更為 Azure 容器應用程式 中已部署應用程式實例的重新導向 URL。 按照下列步驟,在您的 application.yml 檔案中變更這些設定:

  1. 前往應用程式的 src\main\resources\application.yml 檔案,並將 的值變更為已部署應用程式的網域名稱,如下列範例所示。 請務必將 和 替換為您的實際值。 例如,若使用上一個步驟中 Azure Container Apps 環境的預設網域,並以 作為您的應用程式名稱,則您會使用 作為 的值。

    post-logout-redirect-uri: https://<API_NAME>.<default-domain-of-container-app-environment>
    
  2. 儲存此檔案之後,請使用下列命令重建您的應用程式:

    mvn clean package
    

重要

應用程式的 application.yml 檔案目前在 參數中儲存了您的用戶端密鑰值。 將此值保留在這個檔案中並不好的做法。 如果您將檔案提交到 Git 儲存庫,也可能會承擔風險。 如需了解建議的做法,請參閱 在 Azure 容器應用程式 中管理祕密。

更新您的 Microsoft Entra ID 應用程式註冊

由於重新導向 URI 會變更至 Azure 容器應用程式 上已部署的應用程式,因此您也需要變更 Microsoft Entra ID 應用程式註冊中的重新導向 URI。 請使用下列步驟來進行此變更:

  1. 瀏覽至 Microsoft 身分識別平台開發人員適用的 應用程式註冊 頁面。

  2. 使用搜尋方塊搜尋您的應用程式註冊,例如 。

  3. 選取應用程式名稱以開啟您的應用程式註冊。

  4. 從選單中選擇 驗證。

  5. 在 Web重新導向 URI 區段中,選取 新增 URI。

  6. 填入您應用程式的 URI,並在結尾加上 ,例如 。

  7. 選取 儲存。

部署應用程式

將 JAR 套件部署至 AAzure 容器應用程式。

注意

如有必要,您可以在 Java 建置環境變數中指定 JDK 版本。 如需詳細資訊,請參閱 Azure 容器應用程式 中適用於 Java 的建置環境變數。

現在您可以使用 CLI 命令部署 WAR 檔案。

az containerapp up \
    --name $API_NAME \
    --resource-group $RESOURCE_GROUP \
    --location $LOCATION \
    --environment $ENVIRONMENT \
    --artifact <JAR_FILE_PATH_AND_NAME> \
    --ingress external \
    --target-port 8080 \
    --query properties.configuration.ingress.fqdn

注意

預設的 JDK 版本為 17。 如果您需要變更 JDK 版本以便與您的應用程式相容,可以使用 參數來調整版本號碼。

如需其他建置環境變數,請參閱 Azure 容器應用程式 中適用於 Java 的建置環境變數。

驗證應用程式

在此範例中, 命令包含 引數,該引數會傳回完整網域名稱 (FQDN),也稱為應用程式的 URL。 使用下列步驟來檢查應用程式的記錄,以調查任何部署問題:

  1. 在 部署 區段的 輸出 頁面中取得輸出應用程式 URL。

  2. 從 Azure 容器應用程式 執行個體 概觀 頁面的導覽窗格中,選取 記錄 以查看應用程式記錄。

探索範例

使用下列步驟來探索範例:

  1. 請注意畫面中央顯示的已登入或註銷狀態。
  2. 選取角落的情境相關按鈕。 當您第一次開啟應用程式時,此按鈕會顯示為 登入。 或者,選取 權杖詳細資料、僅限管理員或一般使用者。 由於這些頁面受到保護且需要驗證,因此會自動重新導向至登入頁面。
  3. 在下一個頁面上,遵循指示,並使用 Microsoft Entra ID 租使用者中的帳戶登入。
  4. 在同意畫面上,請注意所要求的範圍。
  5. 順利完成登入流程時,您應該重新導向至首頁 ,其中顯示 登入狀態 ,或另一個頁面,視觸發登入流程的按鈕而定。
  6. 請注意,上下文相關按鈕現在會顯示 [註銷 ] 並顯示您的用戶名稱。
  7. 如果您位於首頁,請選取 ID 權杖詳細資料,以查看 ID 權杖中部分已解碼的宣告,包括角色。
  8. 選取 僅限管理員 以檢視 。 只有具有應用程式角色 的使用者才能檢視此頁面。 否則,會顯示授權失敗訊息。
  9. 選取一般使用者以檢視頁面。 只有具有應用程式角色 或 的使用者才能檢視此頁面。 否則,會顯示授權失敗訊息。
  10. 使用角落的按鈕登出。狀態頁面會反映新的狀態。

關於程式碼

此範例示範如何使用 適用於 Java 的 Microsoft Entra ID Spring Boot Starter 用戶端程式庫,讓使用者登入您的 Microsoft Entra ID 租用戶。 此範例也使用了 Spring OAuth2 客戶端和 Spring Web Boot 啟動器。 此範例會使用從 Microsoft Entra ID 取得的 ID 權杖中的宣告來顯示已登入使用者的詳細資料,並使用 roles 宣告進行授權,以限制對某些頁面的存取。

目錄

下表顯示範例項目資料夾的內容:

檔案/資料夾 描述
pom.xml 應用程式相依性。
src/main/resources/templates/ 適用於 UI 的 Thymeleaf 範本。
src/main/resources/application.yml 應用程式與 Microsoft Entra ID 啟動程式庫組態。
src/main/java/com/microsoft/azuresamples/msal4j/msidentityspringbootwebapp/ 此目錄包含主要應用程式進入點、控制器和設定類別。
.../MsIdentitySpringBootWebappApplication.java 主要類別。
.../SampleController.java 具有端點映射的控制器
.../SecurityConfig.java 安全性設定 - 例如,需要驗證的路由。
.../Utilities.java 公用程式類別 - 例如篩選識別碼令牌宣告。
CHANGELOG.md 範例的變更清單。
CONTRIBUTING.md 參與範例的指導方針。
授權' 範例的授權條款。

標識元令牌宣告

為了擷取權杖詳細資料,應用程式會如以下範例所示,在請求對應中使用 Spring Security 的 和 物件。 如需了解此應用程式如何使用 ID 權杖宣告的完整詳細資訊,請參閱 範例控制器。

import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
//...
@GetMapping(path = "/some_path")
public String tokenDetails(@AuthenticationPrincipal OidcUser principal) {
    Map<String, Object> claims = principal.getIdToken().getClaims();
}

在 ID 權杖中處理角色宣告

令牌的角色宣告包含已登入使用者指派的角色名稱,如下列範例所示:

{
  ...
  "roles": [
    "PrivilegedAdmin",
    "RegularUser",]
  ...
}

取得角色名稱的常見方式記載於 ID 權杖宣告 一節。

Microsoft Entra ID Boot Starter v3.3 以及更高版本也會自動解析角色宣告,並將每個角色加入已登入使用者的 ,且在每個角色前方加上字串 。 此設定可讓開發人員透過 方法,在使用 Spring 條件註解時使用應用程式角色。 例如,您可以在 SampleController.java 中找到示範下列 條件的內容:

@GetMapping(path = "/admin_only")
@PreAuthorize("hasAuthority('APPROLE_PrivilegedAdmin')")
public String adminOnly(Model model) {
    // restrict to users who have PrivilegedAdmin app role only
}
@GetMapping(path = "/regular_user")
@PreAuthorize("hasAnyAuthority('APPROLE_PrivilegedAdmin','APPROLE_RegularUser')")
public String regularUser(Model model) {
    // restrict to users who have any of RegularUser or PrivilegedAdmin app roles
}

下列程式代碼會取得指定使用者的完整授權清單:

@GetMapping(path = "/some_path")
public String tokenDetails(@AuthenticationPrincipal OidcUser principal) {
   Collection<? extends GrantedAuthority> authorities = principal.getAuthorities();
}

針對登入,應用程式會向 Microsoft Entra ID Spring Boot Starter 用戶端連結庫 for Java 自動設定Microsoft Entra ID 登入端點提出要求,如下列範例所示:

<a class="btn btn-success" href="/oauth2/authorization/azure">Sign In</a>

若要登出,應用程式會向 端點傳送 POST 要求,如以下範例所示:

<form action="#" th:action="@{/logout}" method="post">
  <input class="btn btn-warning" type="submit" value="Sign Out" />
</form>

依驗證狀態而定的 UI 元素

應用程式在UI範本頁面中有一些簡單的邏輯,可用來根據使用者是否已驗證來判斷要顯示的內容,如下列使用 Spring Security Thymeleaf 標籤的範例所示:

<div sec:authorize="isAuthenticated()">
  this content only shows to authenticated users
</div>
<div sec:authorize="isAnonymous()">
  this content only shows to not-authenticated users
</div>

使用 AADWebSecurityConfigurerAdapter 保護路由

預設情況下,應用程式會保護 ID 權杖詳細資料、僅限管理員 和 一般使用者 頁面,使只有已登入的使用者才能存取這些頁面。 應用程式會根據 application.yml 檔案中的 屬性設定這些路由。 若要設定應用程式的特定需求,您可以在您的其中一個類別中擴充 。 如需範例,請參閱此應用程式的 SecurityConfig 類別,如以下程式碼所示:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends AADWebSecurityConfigurerAdapter{
  @Value( "${app.protect.authenticated}" )
  private String[] protectedRoutes;

    @Override
    public void configure(HttpSecurity http) throws Exception {
    // use required configuration form AADWebSecurityAdapter.configure:
    super.configure(http);
    // add custom configuration:
    http.authorizeRequests()
      .antMatchers(protectedRoutes).authenticated()     // limit these pages to authenticated users (default: /token_details, /admin_only, /regular_user)
      .antMatchers("/**").permitAll();                  // allow all other routes.
    }
}

其他相關資訊

  • Microsoft 身分識別平台文件
  • Microsoft 驗證程式庫 (MSAL) 概觀
  • 快速入門:在 Microsoft 身分識別平台中註冊應用程式
  • 快速入門:設定用戶端應用程式以存取 Web API
  • 瞭解 Microsoft Entra ID 應用程式同意體驗
  • 瞭解使用者和系統管理員同意
  • Azure Active Directory 內的應用程式和服務主體物件
  • 國家雲
  • MSAL 程式碼範例
  • 適用於 Java 的 Azure Active Directory Spring Boot Starter 用戶端程式庫
  • 適用於 Java 的 Microsoft 驗證程式庫 (MSAL4J)
  • MSAL4J 維基
  • ID 權杖
  • Microsoft 身分識別平台中的存取權杖

如需了解 OAuth 2.0 通訊協定如何在此案例及其他案例中運作的詳細資訊,請參閱 Microsoft Entra ID 的驗證案例。