知識庫 / Spring / Spring Security RSS 訂閱

使用 AzureAD 驗證用户身份(Spring Boot)

Cloud,Spring Security
HongKong
9
11:40 AM · Dec 06 ,2025

1. 引言

在本教程中,我們將演示如何輕鬆地使用 AzureAD 作為 Spring Boot 應用程序的身份提供者。

2. 概述

Microsoft 的 Azure AD 是一款全面的身份管理產品,被全球眾多組織廣泛使用。它支持多種登錄機制和控制,為跨組織應用程序組合的用户提供統一身份驗證體驗。

此外,正如 Microsoft 的起源所體現的,Azure AD 與現有的 Active Directory 安裝緊密集成,許多組織已經將其用於企業網絡中的身份和訪問管理。 這使得管理員能夠為現有用户授予應用程序訪問權限,並使用他們熟悉的工具管理其權限。

3. 集成 AzureAD

從 Spring Boot 應用程序的角度來看,AzureAD 作為一個符合 OIDC 標準的身份提供者。這意味着我們可以通過僅配置所需的屬性和依賴項來使用它與 Spring Security 結合使用。

為了説明 AzureAD 的集成,我們將實現一個 授權客户端,其中訪問碼交換髮生在服務器端。 這種流程不會將訪問令牌暴露給用户的瀏覽器,因此它比公共客户端方案更安全。

4. Maven 依賴

我們首先添加用於 Spring Security 基於 WebMVC 應用程序所需的 Maven 依賴項:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
    <version>3.1.5</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.1.5</version>
</dependency>

最新版本的這些依賴項可在 Maven Central 上獲取:

5. 配置屬性

接下來,我們將添加用於配置客户端所需的 Spring Security 屬性。 建議將這些屬性放在一個專門的 Spring 配置文件中,這樣隨着應用程序的增長,維護起來會更容易。 我們將為該配置文件命名為 azuread,以便明確其用途。 因此,我們將相關屬性添加到 application-azuread.yml 文件中:

spring:
  security:
    oauth2:
      client:
        provider:
          azure:
            issuer-uri: https://login.microsoftonline.com/your-tenant-id-comes-here/v2.0
        registration:
          azure-dev:
            provider: azure
            #client-id: externally provided
            #client-secret: externally provided         
            scope:
            - openid
            - email
            - profile

在提供者部分,我們定義了 Azure 提供者。 AzureAD 支持 OIDC 標準端點發現機制,因此我們只需要配置的唯一屬性是 issuer-uri

此屬性具有雙重用途:首先,它是客户端應用程序附加發現資源名稱以獲取實際 URL 的基礎 URI;其次,它還用於驗證 JSON Web Token (JWT) 的真實性。 例如,由身份提供者創建的 JWT 的 iss 聲明必須與 issuer-uri 值相同。

對於 AzureAD,issuer-uri 始終採用格式 https://login.microsoftonline.com/my-tenant-id/v2.0,其中 my-tenant-id 是您租户的標識符。

registration 部分,我們定義了 azure-dev 客户端,它使用先前定義的提供者。 此外,我們必須通過 client-idclient-secret 屬性提供客户端憑據。 我們稍後在本文中涵蓋如何將此應用程序註冊到 Azure 時會返回到這些屬性。

最後,範圍屬性定義了此客户端將包含在授權請求中的範圍集。 在這裏,我們請求 profile 範圍,該範圍允許此客户端應用程序請求標準的 userinfo 端點。 此端點返回 AzureAD 用户目錄中存儲的配置信息集。 這些可能包括用户的首選語言和區域設置數據等。

6. 客户端註冊

正如之前提到的,我們需要在 AzureAD 中註冊我們的客户端應用程序,以獲取所需的屬性的實際值,包括 client-idclient-secret。 假設我們已經擁有一個 Azure 賬户,第一步是登錄到 Web 控制枱,並使用右上角的菜單選擇 Azure Active Directory 服務頁面:

概述 頁面中,我們可以獲取用於 issuer-uri 配置屬性的租户標識符。 接下來,我們將點擊 App Registrations,這將我們帶到現有應用程序的列表,然後點擊“新建註冊”,這將顯示客户端註冊表單。 在這裏,我們必須提供三條信息:

  • 應用程序名稱
  • 支持的帳户類型
  • 重定向 URI

讓我們詳細説明這些項目。

6.1. 應用程序名稱

此處的值將在身份驗證過程中向最終用户顯示。因此,我們應該選擇一個對目標受眾有意義的名稱。我們使用一個非常不具創意的名稱:“Baeldung Test App”:

我們不必太在意名稱是否正確。 AzureAD 允許我們隨時更改它,而不會影響已註冊的應用程序。 重要的是要注意,雖然此名稱不必是唯一的,但使用多個應用程序採用相同的顯示名稱並不是一個好主意。

6.2. 支持的賬户類型

這裏提供了一些選項,您可以根據應用程序的目標受眾進行選擇。 對於旨在用於組織內部使用的應用程序,通常我們希望選擇“僅在組織目錄中”的選項。這意味着即使應用程序可以從互聯網訪問,只有組織內的用户才能登錄:

其他可用的選項可以添加接受來自其他 AzureAD 支持目錄的用户(例如,任何使用 Office 365 和 Skype 以及/或 Xbox 上的個人賬户的學校或組織)的功能。

雖然這種設置不常見,但您仍然可以在稍後更改此設置,但如文檔所述,更改後可能會出現錯誤消息。

6.3. 重定向 URI

最後,我們需要提供一個或多個可接受的授權流程目標重定向 URI。 必須選擇與 URI 關聯的“平台”,這對應於我們正在註冊的應用程序的類型:

  • Web:授權碼與訪問令牌交換髮生在後端
  • SPA:授權碼與訪問令牌交換髮生在前端
  • 公共客户端:用於桌面和移動應用程序。

在我們的情況下,我們將選擇第一個選項,因為它符合我們用於用户身份驗證的需求。

至於 URI,我們將使用值 http://localhost:8080/login/oauth2/code/azure-dev。 此值來自 Spring Security OAuth 調用的回調控制器路徑,默認情況下,它期望響應代碼在 /login/oauth2/code/{registration-name} 處。 其中,{registration-name} 必須與 registration 部分的鍵中存在的值匹配,在本例中是 azure-dev

此外,AzureAD 要求使用 HTTPS 進行這些 URI,但對於 localhost 存在例外。 這使本地開發無需設置證書。 稍後,當我們遷移到目標部署環境(例如 Kubernetes 集羣)時,我們可以添加額外的 URI。

請注意,此鍵的值與 AzureAD 的註冊名稱無關,儘管使用與它使用的位置相關的名稱是有意義的。

6.4. 添加客户端密鑰

在初始註冊表單上按下注冊按鈕後,我們將看到客户端信息頁面:

“Essentials” 部分包含左側的應用程序 ID,對應於我們屬性文件中 client-id 屬性。要生成新的客户端密鑰,我們現在點擊 Add a certificate or secret,這將我們帶到“Certificates & Secrets” 頁面。接下來,我們選擇 Client Secrets 選項卡,然後點擊 New client secret 以打開密鑰創建表單:

在這裏,我們將為這個密鑰提供一個描述性的名稱,並定義其到期日期。我們可以從預配置的持續時間中選擇,或者選擇自定義選項,這允許我們定義開始和結束日期。

截至本文撰寫時,客户端密鑰最長有效期為兩年。這意味着我們必須建立一個密鑰輪換程序,最好使用自動化工具,如 Terraform。 兩年可能看起來很長,但在企業環境中,在被替換或更新之前運行多年的應用程序非常常見。

在點擊 Add 後,新創建的密鑰將顯示在客户端憑據列表中:

我們必須立即將密鑰值複製到安全的地方,因為離開此頁面後將不再顯示它。 在我們的情況下,我們將直接將值複製到應用程序的屬性文件中,在 client-secret 屬性下。

總之,請記住這是一個敏感值!在將應用程序部署到生產環境中,此值通常通過某種動態機制提供,例如 Kubernetes 密鑰。

7. 應用代碼

我們的測試應用有一個單一的控制器,用於處理到根路徑的請求,記錄有關傳入身份驗證的信息,並將請求轉發到 Thymeleaf 視圖。 在那裏,它將渲染包含當前用户信息的頁面。

實際控制器的代碼非常簡單:

@Controller
@RequestMapping("/")
public class IndexController {

    @GetMapping
    public String index(Model model, Authentication user) {
        model.addAttribute("user", user);
        return "index";
    }
}

視圖代碼使用 user 模型屬性來創建一個包含身份驗證對象和所有可用聲明信息的漂亮表格。

8. 運行測試應用程序

所有組件已就緒後,現在可以運行應用程序。 由於我們使用了帶有 AzureAD 屬性的特定配置文件,因此需要激活它。 通過使用 Spring Boot 的 Maven 插件運行應用程序時,可以使用 spring-boot.run.profiles 屬性來完成:

mvn -Dspring-boot.run.profiles=azuread spring-boot:run

現在,我們可以打開瀏覽器並訪問 http://localhost:8080。 Spring Security 會檢測到該請求尚未進行身份驗證,並將其重定向到 AzureAD 的通用登錄頁面:

具體的登錄序列會根據組織的設置而有所不同,但通常包括填寫用户名或電子郵件以及提供憑據。如果配置允許,它還可以請求第二個身份驗證因素。但是,如果我們當前已在同一 AzureAD 租户的同一瀏覽器中登錄到另一個應用程序,則會跳過登錄序列——這正是單點登錄的本質所在。

首次訪問我們的應用程序時,AzureAD 還會顯示應用程序的授權請求表單:

雖然此處未涵蓋,但 AzureAD 支持自定義登錄 UI 的多個方面,包括地區特定定製。 此外,還可以完全跳過授權表單,這在授權內部應用程序時非常有用。

在授予權限後,我們將看到應用程序的主頁,如下所示:

我們可以看到,我們已經可以訪問有關用户的基本信息,包括姓名、電子郵件,甚至用於檢索其照片的 URL。 然而,有一個令人討厭的細節:Spring 選擇的用户名值不夠友好。

讓我們看看如何改進它。

9. 用户名映射

Spring Security 使用 <em >Authentication</em > 接口來表示經過身份驗證的 <em >Principal</em >>。 這種接口的實現必須提供getName()> 方法,該方法返回的值通常用作身份驗證域中用户唯一的標識符。

當使用基於 JWT 的身份驗證時,Spring Security 默認情況下將使用標準的 `sub> 主題聲明值作為 `Principal> 的名稱。 查看主題聲明,我們看到 AzureAD 將此字段填充為內部標識符,這不適合顯示目的。

幸運的是,在這種情況下有一個簡單的解決方案。 只需要選擇可用的屬性並將其名稱放在提供程序的 `user-name-attribute> 屬性中:

spring:
  security:
    oauth2:
      client:
        provider:
          azure:
            issuer-uri: https://login.microsoftonline.com/xxxxxxxxxxxxx/v2.0
            user-name-attribute: name
... other properties omitted

在此,我們選擇了“claim”這個名稱,因為它與用户的完整名稱相對應。另一個合適的候選者是 email 屬性,如果我們的應用程序需要將其值作為數據庫查詢的一部分使用,則它可能是一個不錯的選擇。

現在我們可以重啓應用程序,查看這種更改的影響:

現在好多了!

10. 獲取組成員身份

更仔細地檢查可用的聲明顯示,沒有關於用户組成員身份的信息。 唯一的 GrantedAuthority 值在 Authentication 中是與請求的範圍相關的,作為客户端配置的一部分。

如果所有我們需要的只是限制組織成員的訪問權限,那麼這可能就足夠了。 但是,通常情況下,我們會根據當前用户的角色分配授予不同的訪問級別。 此外,將這些角色映射到 AzureAD 組可以重用現有的流程,例如用户註冊和/或重新分配。

為了實現這一點,我們必須指示 AzureAD 將組成員身份包含在我們將接收到的 idToken 中。

首先,我們需要前往應用程序的頁面並選擇右側菜單中的 Token Configuration。 然後,我們點擊 Add groups claim,這會打開一個對話框,其中我們將定義此聲明類型的詳細信息:

我們將使用常規 AzureAD 組,因此選擇第一個選項 (“Security Groups”)。 此對話框還具有每個受支持的令牌類型的其他配置選項。 我們目前將保留默認值。

一旦我們點擊 Save,應用程序的聲明列表將顯示組聲明:

現在,我們可以返回到我們的應用程序以查看此配置的效果:

11. 將組映射到 Spring 權限

組聲明包含與用户分配的組對應的對象標識符列表。然而,Spring 並不會自動將這些組映射到 GrantedAuthority 實例中。

要執行此操作,需要一個自定義的 OidcUserService,如 Spring Security 的 文檔中所述。我們的實現使用外部映射來“豐富”標準 OidcUser 實現,添加額外的權限。我們使用一個 @ConfigurationProperties 類來存儲所需的信息:

  • 從我們從中獲取組列表的聲明名稱 (“groups”)
  • 映射自此提供程序的權限前綴
  • 對象標識符到 GrantedAuthority 值的映射

使用組到列表的映射策略允許我們處理希望使用現有組的情況。它也有助於保持應用程序的角色集與組分配策略分離。

以下是一個典型的配置示例:

baeldung:
  jwt:
    authorization:
      group-to-authorities:
        "ceef656a-fca9-49b6-821b-xxxxxxxxxxxx": BAELDUNG_RW
        "eaaecb69-ccbc-4143-b111-xxxxxxxxxxxx": BAELDUNG_RO,BAELDUNG_ADMIN

對象標識符可在 頁面上找到:

完成所有映射後並重啓我們的應用程序,我們就可以測試應用程序。這是屬於兩個組的用户獲得的測試結果:

現在它擁有三個新的權威,對應於映射的組。

12. 結論

在本文中,我們展示瞭如何使用 AzureAD 與 Spring Security 身份驗證用户,包括用於演示應用程序所需的配置步驟。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.