將使用 Azure Active Directory B2C 的登入功能新增到 Spring Web 應用程式
本文說明如何使用 Spring Initializr 搭配 spring Boot Starter for Microsoft Entra ID,建立具有登入功能的 Java 應用程式。
在本教學課程中,您將瞭解如何:
- 使用 Spring Initializr 建立 Java 應用程式
- 設定 Azure Active Directory B2C
- 使用 Spring Boot 類別和批註保護應用程式
- 建置及測試Java應用程式
Microsoft Entra ID 是 Microsoft雲端規模的企業身分識別解決方案。 Azure Active Directory B2C 補充 Microsoft Entra 身份識別的功能集,讓您能夠管理客戶、消費者和公民對您的企業對消費者 (B2C) 應用程式的存取。
先決條件
- Azure 訂用帳戶。 如果您還沒有帳戶,請在開始之前建立 免費帳戶。
- 支援的 Java 開發工具套件 (JDK)。 如需在 Azure 上開發時可用的 JDK 詳細資訊,請參閱 Azure 和 Azure Stack 上的 Java 支援。
- Apache Maven3.0 版或更高版本。
重要
需要 Spring Boot 2.5 版或更高版本,才能完成本文中的步驟。
使用 Spring Initializr 建立應用程式
根據本指引填寫值。 標籤和版面配置可能與此處顯示的影像不同。
- 在 [項目] 下,選取 [Maven 專案]。
- 在 [語言] 下,選取 [Java]。
- 在 [Spring Boot下,選取 [2.7.11]。
- 在 群組、產物 和 名稱 中,輸入相同的值,並使用簡短的描述字串。 當您輸入時,UI 可能會自動填入其中一些欄位。
- 在 [相依性] 窗格中,選取 [新增相依性]。 使用用戶介面在 Spring Web 和 Spring Security上新增相依性。
注意
Spring Security 5.5.1、5.4.7、5.3.10 和 5.2.11 已發行,以解決下列 CVE 報告中的問題,CVE-2021-22119:使用 spring-security-oauth2-client阻斷服務攻擊。 如果您使用舊版,請加以升級。
選取 [產生專案],然後將專案下載到本機電腦上的路徑。 將下載的檔案移至以專案命名的目錄,並將檔案解壓縮。 檔案配置看起來應該像下面這樣,而您為 Group 輸入的值會取代
yourProject
。. ├── HELP.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main │ ├── java │ │ └── yourProject │ │ └── yourProject │ │ └── YourProjectApplication.java │ └── resources │ ├── application.properties │ ├── static │ └── templates └── test └── java └── yourProject └── yourProject └── YourProjectApplicationTests.java
建立和初始化Microsoft Entra 實例
建立 Active Directory 實例
選擇 [建立資源。 搜尋 Azure Active Directory B2C。
選擇 建立。
選擇 建立新的 Azure AD B2C 租使用者。
針對 組織名稱 和 初始網域名稱提供適當的值,然後選取 建立。
當您完成 Active Directory 的建立後,請選取右上角的帳戶,然後選擇 [切換目錄],再選取您建立的目錄。 系統會將您重新導向至新的租使用者首頁。 然後搜尋
b2c
,接著選取 [Azure AD B2C]。
新增 Spring Boot 應用程式的應用程式註冊
在 [管理] 窗格中,選取 [應用程式註冊],然後選取 [[新增註冊]。
在 [名稱] 欄位中,輸入您的應用程式名稱,然後選取 註冊。
回到 [管理] 窗格,選取 [應用程式註冊 ],然後選取您建立的應用程式名稱。
選取 [驗證],然後 [新增平臺],接著 [Web]。 將 [重新導向 URI] 設定為 [
http://localhost:8080/login/oauth2/code/
],然後選取 [設定]。
為您的應用程式新增應用程式秘密
選取 [憑證] & [密碼],然後 [新增客戶端密碼]。 輸入您的秘密描述,然後選擇 新增。 建立秘密之後,請選取秘密值旁的複製圖示,複製值以供本文稍後使用。
注意
如果您離開 [憑證 & 秘密] 區段並返回,您將看不到秘密值。 在此情況下,您必須建立另一個秘密,並複製它以供日後使用。 有時候,產生的秘密值可能會包含某些對 application.yml 檔案有問題的字元,例如反斜線或反引號。 在此情況下,捨棄該密碼並產生另一個密碼。
新增使用者流程
導航至您的租戶首頁。 在左窗格的 [原則] 區段中,選取 [使用者流程],然後選取 [[新增使用者流程]。
您現在將離開本教學課程、執行另一個教學課程,並在完成時返回本教學課程。 當您前往其他教學課程時,以下是一些要記住的事項。
- 請從要求您選擇 [新增使用者流程]的步驟開始。
- 當本教學課程參考
webapp1
時,請改用您為 群組 輸入的值。 - 當您選取要從流程傳回的宣告時,請確定已選取 顯示名稱。 如果沒有此宣告,本教學課程中正在建置的應用程式將無法運作。
- 當系統要求您執行使用者流程時,您先前指定的重新導向 URL 尚未作用中。 您仍然可以執行流程,但重新導向無法順利完成。 這是預期的。
- 當您觸達「後續步驟」時,請返回本教學課程。
遵循 教學課程:在 Azure Active Directory B2C 中建立使用者流程,以建立「註冊和登入」、「配置檔編輯」和「密碼重設」的使用者流程。
Azure AD B2C 支援本機帳戶和社交識別提供者。 如需建立 GitHub 識別提供者的範例,請參閱 使用 Azure Active Directory B2C設定 GitHub 帳戶的註冊和登入。
設定和編譯您的應用程式
既然您已建立 Azure AD B2C 實例和一些使用者流程,您將將 Spring 應用程式連線到 Azure AD B2C 實例。
從命令行中使用 cd 指令切換到您解壓縮從 Spring Initializr 下載的 .zip 檔案的目錄。
流覽至專案的父資料夾,然後在文本編輯器中開啟 pom.xml Maven 項目檔。
將 Spring OAuth2 安全性的相依性新增至 pom.xml:
<dependency> <groupId>com.azure.spring</groupId> <artifactId>spring-cloud-azure-starter-active-directory-b2c</artifactId> <version>See Below</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version>See Below</version> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> <version>See Below</version> </dependency>
針對
spring-cloud-azure-starter-active-directory-b2c
,請使用可用的最新版本。 您或許可以使用 mvnrepository.com 來查閱。至於
spring-boot-starter-thymeleaf
,請使用與您上面選取的 Spring Boot 版本相對應的版本,例如2.3.4.RELEASE
。針對
thymeleaf-extras-springsecurity5
,請使用可用的最新版本。 您可以使用 mvnrepository.com 來查找。 從本文撰寫起,最新版本是3.0.4.RELEASE
。儲存並關閉 pom.xml 檔案。
- 請執行
mvn -DskipTests clean install
,以確認您的依賴是否正確。 如果您沒有看到BUILD SUCCESS
,請先進行疑難解答並解決問題,然後再繼續。
- 請執行
流覽至專案中 src/main/resources 資料夾,並在文本編輯器中建立 application.yml 檔案。
使用您稍早建立的值來指定應用程式註冊的設定;例如:
spring: cloud: azure: active-directory: b2c: enabled: true base-uri: https://<your-tenant-initial-domain-name>.b2clogin.com/<your-tenant-initial-domain-name>.onmicrosoft.com/ credential: client-id: <your-application-ID> client-secret: '<secret-value>' login-flow: sign-up-or-sign-in logout-success-url: <your-logout-success-URL> user-flows: sign-up-or-sign-in: <your-sign-up-or-sign-in-user-flow-name> profile-edit: <your-profile-edit-user-flow-name> password-reset: <your-password-reset-user-flow-name> user-name-attribute-name: <your-user-name-attribute-name>
請注意,
client-secret
值會以單引弧括住。 這是必要的,因為<secret-value>
的值幾乎肯定會包含一些字元,當它們出現在 YAML 中時,需要在單引號內。注意
撰寫本文時,可用於 application.yml 的 Active Directory B2C Spring Integration 值完整清單如下:
spring: cloud: azure: active-directory: b2c: enabled: true base-uri: credential: client-id: client-secret: login-flow: logout-success-url: user-flows: sign-up-or-sign-in: profile-edit: # optional password-reset: # optional user-name-attribute-name:
儲存並關閉 application.yml 檔案。
在 src/main/java/<yourGroupId>/<yourGroupId>中,建立一個名為 控制器 的資料夾,並將
<yourGroupId>
替換成您為 Group輸入的值。在 控制器 資料夾中建立名為 WebController.java 的新 Java 檔案,並在文字編輯器中開啟它。
輸入下列程式代碼,適當地變更
yourGroupId
,然後儲存並關閉檔案:package yourGroupId.yourGroupId.controller; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class WebController { private void initializeModel(Model model, OAuth2AuthenticationToken token) { if (token != null) { final OAuth2User user = token.getPrincipal(); model.addAttribute("grant_type", user.getAuthorities()); model.addAllAttributes(user.getAttributes()); } } @GetMapping(value = "/") public String index(Model model, OAuth2AuthenticationToken token) { initializeModel(model, token); return "home"; } @GetMapping(value = "/greeting") public String greeting(Model model, OAuth2AuthenticationToken token) { initializeModel(model, token); return "greeting"; } @GetMapping(value = "/home") public String home(Model model, OAuth2AuthenticationToken token) { initializeModel(model, token); return "home"; } }
由於控制器中的每個方法都會呼叫
initializeModel()
,而且該方法會呼叫model.addAllAttributes(user.getAttributes());
,因此 src/main/resources/templates 中的任何 HTML 頁面都能夠存取任何這些屬性,例如${name}
、${grant_type}
或${auth_time}
。 從user.getAttributes()
傳回的值實際上是驗證id_token
的宣告。 可用宣告的完整清單會列在 Microsoft 身分識別平台標識碼令牌中。在 src/main/java/<yourGroupId>/<yourGroupId>中建立名為 security 的資料夾,並將
yourGroupId
取代為您為 Group輸入的值。在 安全性 資料夾中建立名為 WebSecurityConfiguration.java 的新 Java 檔案,並在文本編輯器中開啟它。
輸入下列程式代碼,適當地變更
yourGroupId
,然後儲存並關閉檔案:package yourGroupId.yourGroupId.security; import com.azure.spring.cloud.autoconfigure.aadb2c.AadB2cOidcLoginConfigurer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @EnableWebSecurity public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { private final AadB2cOidcLoginConfigurer configurer; public WebSecurityConfiguration(AadB2cOidcLoginConfigurer configurer) { this.configurer = configurer; } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest() .authenticated() .and() .apply(configurer) ; } }
將 home.html 檔案從 spring-cloud-azure-starter-active-directory-b2c 範例:aad-b2c-web-application 複製到 src/main/resources/templates,並以您稍早建立的使用者流程名稱取代
${your-profile-edit-user-flow}
和${your-password-reset-user-flow}
。
建置和測試您的應用程式
開啟命令提示字元,並將目錄變更為應用程式 pom.xml 檔案所在的資料夾。
使用 Maven 建置 Spring Boot 應用程式並加以執行;例如:
注意
本機 Spring Boot 應用程式運行時所依賴的系統時鐘時間的準確性極其重要。 使用 OAuth 2.0 時,時鐘扭曲的容錯度很小。 即使只有三分鐘的誤差也可能導致登入失敗,並出現類似
[invalid_id_token] An error occurred while attempting to decode the Jwt: Jwt used before 2020-05-19T18:52:10Z
的錯誤。 截至撰寫本文時,time.gov 有一個指標,顯示您時鐘與正確時間的誤差。 應用程式已成功執行,誤差為 +0.019 秒。mvn -DskipTests clean package mvn -DskipTests spring-boot:run
在 Maven 建置並啟動您的應用程式之後,在網頁瀏覽器中開啟
http://localhost:8080/
;您應該重新導向至登入頁面。選取與登入相關的文字連結。 您應該會被重新導向至 Azure AD B2C 以啟動驗證流程。
成功登入之後,您應該會看到來自瀏覽器的範例
home page
,
故障排除
下列各節說明如何解決您可能會遇到的一些問題。
屬性中遺漏屬性名稱
在執行範例時,您可能會收到訊息為 Missing attribute 'name' in attributes
的例外狀況。 此例外狀況的記錄看起來會類似下列輸出:
java.lang.IllegalArgumentException: Missing attribute 'name' in attributes
at org.springframework.security.oauth2.core.user.DefaultOAuth2User.<init>(DefaultOAuth2User.java:67) ~[spring-security-oauth2-core-5.3.6.RELEASE.jar:5.3.6.RELEASE]
at org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser.<init>(DefaultOidcUser.java:89) ~[spring-security-oauth2-core-5.3.6.RELEASE.jar:5.3.6.RELEASE]
at org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService.loadUser(OidcUserService.java:144) ~[spring-security-oauth2-client-5.3.6.RELEASE.jar:5.3.6.RELEASE]
at org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService.loadUser(OidcUserService.java:63) ~[spring-security-oauth2-client-5.3.6.RELEASE.jar:5.3.6.RELEASE]
如果您遇到此錯誤,請再詳加檢查您在 教學課程:在 Azure Active Directory B2C中建立的使用者流程。 建立使用者工作流程時,針對 使用者屬性和宣告,請務必選擇用於 顯示名稱的屬性和宣告。 此外,請務必在 application.yml 檔案中正確設定 user-name-attribute-name
。
使用迴圈登入 B2C 端點
此問題很可能是因為 localhost
受到污染的 Cookie 所造成。 清除 localhost
的 Cookie,然後再試一次。
總結
在本教學課程中,您已使用 Azure Active Directory B2C 入門版建立新的 Java Web 應用程式、設定新的 Azure AD B2C 租使用者,並在其中註冊新的應用程式,然後將您的應用程式設定為使用 Spring 註釋和類別來保護 Web 應用程式。
清除資源
不再需要時,請使用 Azure 入口網站 刪除本文中建立的資源,以避免產生非預期的費用。
後續步驟
若要深入瞭解 Spring 和 Azure,請繼續前往 Azure 上的 Spring 檔中心。