使用 Azure Active Directory B2C 保护 Java Spring Boot 应用
本文演示了一个 Java Spring Boot Web 应用,它使用适用于 Java 的 Azure AD B2C Spring Boot Starter 客户端库在 Azure Active Directory B2C 租户上登录用户。 它使用 OpenID Connect 协议。
下图显示了应用的拓扑结构:
客户端应用使用适用于 Java 的 Azure AD B2C Spring Boot Starter 客户端库登录用户,并从 Azure AD B2C 获取 ID 令牌。 ID 令牌证明用户已通过 Azure AD B2C 的身份验证,并让用户能够访问受保护的路由。
先决条件
- JDK 版本 15。 本示例是在使用 Java 15 的系统上开发的,但可能与其他版本兼容。
- Maven 3
- 建议在 Visual Studio Code 中运行此示例时使用适用于 Visual Studio Code 的 Java 扩展包。
- Azure AD B2C 租户。 有关详细信息,请参阅教程:创建 Azure Active Directory B2C 租户
- Visual Studio Code
- Azure Tools for Visual Studio Code
建议
- 熟悉一下 Spring Framework。
- 熟悉一下 Linux/OSX 终端。
- 用于检查令牌的 jwt.ms。
- 用于监控网络活动和故障排除的 Fiddler。
- 关注 Microsoft Entra ID 博客,了解最新进展情况。
设置示例
以下各部分将介绍如何设置示例应用程序。
克隆或下载示例存储库
要克隆示例,请打开 Bash 窗口并使用以下命令:
git clone https://github.com/Azure-Samples/ms-identity-msal-java-samples.git
cd 4-spring-web-app/1-Authentication/sign-in-b2c
或者,导航到 ms-identity-msal-java-samples 存储库,然后将其作为 .zip 文件下载并提取到硬盘驱动器。
重要
为避免 Windows 系统对文件路径长度的限制,请将存储库克隆提取到硬盘驱动器根目录附近。
此示例介绍了一个用于演示的预注册应用程序。 如果想使用自己的 Azure AD B2C 租户和应用程序,请在 Azure 门户中注册和配置应用程序。 有关详细信息,请参阅注册应用部分。 否则,继续执行运行样本部分中的步骤。
选择要在其中创建应用程序的 Azure AD B2C 租户
要选择租户,请按以下步骤操作:
登录到 Azure 门户。
如果你的帐户存在于多个 Azure AD B2C 租户中,请在 Azure 门户的角落里选择配置文件,然后选择“切换目录”,将会话更改为所需的 Azure AD B2C 租户。
创建用户流和自定义策略
要创建注册、登录、配置文件编辑和密码重置等常用用户流,请参阅教程:在 Azure Active Directory B2C 中创建用户流。
还应考虑在 Azure Active Directory B2C 中创建自定义策略。 但是,此任务超出了本教程的范围。 有关详细信息,请参阅 Azure AD B2C 自定义策略概述。
添加外部标识提供者
请参阅教程:将标识提供者添加到 Azure Active Directory B2C 应用程序。
注册应用 (java-spring-webapp-auth-b2c)
要注册应用,请按照以下步骤操作:
导航到 Azure 门户,选择“Azure AD B2C”。
在导航窗格中选择“应用注册”,然后选择“新注册”。
在出现的“注册应用程序”页面中,输入以下应用程序注册的信息:
- 在“名称”部分中,输入一个有意义的应用名称,以便向应用用户显示,例如 。
java-spring-webapp-auth-b2c
- 在“支持的帐户类型”下,选择“任何标识提供者或组织目录中的帐户(用于通过用户流对用户进行身份验证)” 。
- 在“重定向 URI(可选)”部分的组合框中选择“Web”,然后输入以下重定向 URI:。
http://localhost:8080/login/oauth2/code/
- 在“名称”部分中,输入一个有意义的应用名称,以便向应用用户显示,例如 。
选择“注册”以创建应用程序。
在应用的注册页面上,找到并复制“应用程序(客户端) ID”值,以供稍后使用。 可以在应用程序的一个或多个配置文件中使用此值。
选择“保存”以保存更改。
在应用的注册页面上,选择导航窗格中的“证书和机密”窗格,打开可生成机密和上传证书的页面。
在“客户端密码”部分中,选择“新建客户端密码”。
键入描述,例如“应用机密”。
根据你的安全考虑,从可用期限中选择一个,例如在 2 年内。
选择 添加 。 此时将显示生成的值。
复制并保存生成的值,以供在之后的步骤中使用。 代码的配置文件需要使用此值。 此值不会再显示,也无法通过任何其他方式获取。 因此,在导航到任何其他屏幕或窗格之前,请务必从 Azure 门户保存该值。
配置应用 (java-spring-webapp-auth-b2c) 以使用应用注册
按照以下步骤来配置应用:
注意
在以下步骤中,ClientID
与 Application ID
或 AppId
相同。
在 IDE 中打开项目。
打开 src/main/resources/application.yml 文件。
找到
client-id
属性,然后用 Azure 门户中clientId
应用程序的应用程序 ID 或java-spring-webapp-auth-b2c
替换现有值。找到
client-secret
属性,并将现有值替换为在 Azure 门户创建java-spring-webapp-auth-b2c
应用程序时保存的值。找到
base-uri
属性,并将值fabrikamb2c
的两个实例替换为在 Azure 门户中创建java-spring-webapp-auth-b2c
应用程序的 Azure AD B2C 租户的名称。找到
sign-up-or-sign-in
属性,并将其替换为在 Azure 门户中创建java-spring-webapp-auth-b2c
应用程序的 Azure AD B2C 租户中创建的注册/登录用户流策略的名称。找到
profile-edit
属性,并将其替换为在 Azure 门户中创建java-spring-webapp-auth-b2c
应用程序的 Azure AD B2C 租户中创建的密码重置用户流策略的名称。找到
password-reset
属性,并将其替换为在 Azure 门户中创建java-spring-webapp-auth-b2c
应用程序的 Azure AD B2C 租户中创建的编辑配置文件用户流策略的名称。打开 src/main/resources/templates/navbar.html 文件。
查找对
b2c_1_susi
和b2c_1_edit_profile
流的引用,并以sign-up-sign-in
和profile-edit
用户流替换掉它们。
运行示例
以下各部分将展示如何将示例部署到 Azure 容器应用。
先决条件
- 一个 Azure 帐户。 如果没有帐户,请创建一个免费帐户。 你需要拥有 Azure 订阅的
Contributor
或Owner
权限才能继续操作。 有关详细信息,请参阅使用 Azure 门户分配 Azure 角色。 - Azure CLI。
- Azure 容器应用 CLI 扩展,版本
0.3.47
或更高。 要安装最新版本,请使用az extension add --name containerapp --upgrade --allow-preview
命令。 - Java 开发工具包,版本 17 或更高。
- Maven。
准备 Spring 项目
使用以下步骤来准备项目:
使用以下 Maven 命令生成项目:
mvn clean verify
使用以下命令在本地运行示例项目:
mvn spring-boot:run
安装
要从 CLI 登录到 Azure,请运行以下命令,然后按照提示完成身份验证过程。
az login
为了确保运行最新版本的 CLI,请运行升级命令。
az upgrade
接下来,安装或更新适用于 CLI 的 Azure 容器应用扩展。
如果在 Azure CLI 中运行 az containerapp
命令时收到有关缺少参数的错误,请确保已安装最新版本的 Azure 容器应用扩展。
az extension add --name containerapp --upgrade
注意
从 2024 年 5 月开始,Azure CLI 扩展不再默认启用预览功能。 要访问容器应用预览功能,请使用 --allow-preview true
安装容器应用扩展。
az extension add --name containerapp --upgrade --allow-preview true
现在已安装当前扩展或模块,接下来请注册 Microsoft.App
和 Microsoft.OperationalInsights
命名空间。
注意
Azure 容器应用资源已从 Microsoft.Web
命名空间迁移到 Microsoft.App
命名空间。 有关详细信息,请参阅 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 \
使用自动生成的日志分析工作区创建环境。
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 文件中的这些设置:
导航到应用程序的 src\main\resources\application.yml 文件,并将
post-logout-redirect-uri
的值更改为已部署应用的域名,如下例所示。 请务必用实际值替换<API_NAME>
和<default-domain-of-container-app-environment>
。 例如,使用上一步中 Azure 容器应用环境的默认域和应用名称ms-identity-api
,将使用https://ms-identity-api.<default-domain>
作为post-logout-redirect-uri
的值。post-logout-redirect-uri: https://<API_NAME>.<default-domain-of-container-app-environment>
保存此文件后,使用以下命令重新生成应用:
mvn clean package
重要
应用程序的 application.yml 文件当前在 client-secret
参数中保存了客户机密的值。 在此文件中保留此值并非良好做法。 如果将文件提交到 Git 存储库,则也可能面临风险。 有关建议的方法,请参阅管理 Azure 容器应用中的机密。
更新 Microsoft Entra ID 应用注册
由于重定向 URI 会更改为在 Azure 容器应用上部署的应用,因此还需要更改 Microsoft Entra ID 应用注册中的重定向 URI。 要进行此更改,请使用以下步骤:
导航到面向开发人员的 Microsoft 标识平台应用注册页。
使用搜索框搜索应用注册,例如
java-servlet-webapp-authentication
。选择应用名称,打开应用注册。
从菜单中选择“身份验证”。
在 Web - 重定向 URI 部分中,选择“添加 URI”。
填写应用程序的 URI,附加
/login/oauth2/code/
- 例如https://<containerapp-name>.<default domain of container app environment>/login/oauth2/code/
。选择“保存”。
部署应用
将 JAR 包部署到 Azure 容器应用。
注意
如有必要,可以在 Java 生成环境变量中指定 JDK 版本。 有关详细信息,请参阅 在 Azure 容器应用中为 Java 生成环境变量。
现在,可以使用 CLI 命令 az containerapp up
部署 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 版本以与应用程序兼容,可以使用 --build-env-vars BP_JVM_VERSION=<YOUR_JDK_VERSION>
参数来调整版本号。
有关生成环境变量的详细信息,请参阅 在 Azure 容器应用中为 Java 生成环境变量。
验证应用
在此示例中,containerapp up
命令包含 --query properties.configuration.ingress.fqdn
参数,该参数会返回完全限定的域名 (FQDN),也称为应用的 URL。 按以下步骤检查应用程序的日志,以调查任何部署问题:
从“部署”部分的“输出”页面访问输出应用程序 URL。
在 Azure 容器应用实例“概述”页面的导航窗格中,选择“日志”以检查应用的日志。
探索示例
按照以下步骤来探索示例:
- 注意屏幕中央显示的登录或退出状态。
- 选择角落里的上下文相关按钮。 首次运行应用时,此按钮显示“登录”。 或者,选择令牌详细信息的链接。 由于此页面受保护并需要身份验证,因此你会被自动重定向到登录页面。
- 在下一页中,按照说明使用所选身份供应程序的帐户登录。 也可以选择使用电子邮件地址注册或登录 B2C 租户的本地帐户。
- 成功完成登录流程后,你将被重定向到主页(显示“登录状态”)或“令牌详细信息”页面,这取决于哪个按钮触发了你的登录流。
- 请注意,上下文相关按钮现在显示“注销”并显示你的用户名。
- 如果是在主页上,请选择“ID 令牌详细信息”,以便查看 ID 令牌的一些已解码声明。
- 编辑个人资料。 选择“编辑个人资料”,以便以更改显示名称、居住地和职业等详细信息。
- 使用角落的按钮注销。状态页面会显示新的状态。
关于代码
此示例演示了如何使用适用于 Java 的 Azure AD B2C Spring Boot Starter 客户端库将用户登录到 Azure AD B2C 租户。 此示例还使用了 Spring Oauth2 Client 和 Spring Web Boot Starter。 此示例使用从 Azure AD B2C 获取的 ID 令牌中的声明来显示已登录用户的详细信息。
目录
下表列出了示例项目文件夹的内容:
文件/文件夹 | 说明 |
---|---|
pom.xml | 应用程序依赖项。 |
src/main/resources/templates/ | 适用于 UI 的 Thymeleaf 模板。 |
src/main/resources/application.yml | 应用程序和 Microsoft Entra Boot Starter 库配置。 |
src/main/java/com/microsoft/azuresamples/msal4j/msidentityspringbootwebapp/ | 此目录包含主应用程序入口点、控制器和配置类。 |
.../MsIdentitySpringBootWebappApplication.java | 主类。 |
.../SampleController.java | 带有终结点映射的控制器。 |
.../SecurityConfig.java | 安全配置 - 例如,哪些路由需要身份验证。 |
.../Utilities.java | 实用工具类 - 例如,筛选器 ID 令牌声明。 |
CHANGELOG.md | 示例更改的列表。 |
CONTRIBUTING.md | 参与示例的指南。 |
许可证 | 示例的许可证。 |
ID 令牌声明
为了提取令牌详细信息,应用在请求映射中使用了 Spring Security 的 AuthenticationPrincipal
和 OidcUser
对象,如下例所示。 有关此应用如何使用 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();
}
登录和注销链接
对于登录,应用会向适用于 Java 的 Azure AD B2C Spring Boot Starter 客户端库自动配置的 Azure AD B2C 登录终结点发出请求,如下例所示:
<a class="btn btn-success" href="/oauth2/authorization/{your-sign-up-sign-in-user-flow}">Sign In</a>
对于注销,应用会向 logout
终结点发出 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>
使用 WebSecurityConfigurerAdapter 保护路由
默认情况下,应用会保护“ID 令牌详细信息”页面,只有已登录的用户才能访问该页面。 应用会通过 app.protect.authenticated
文件中的 属性来配置这些路由。 要配置应用的特定需求,可以在其中一个类中扩展 WebSecurityConfigurerAdapter
。 例如,请参阅此应用程序的 SecurityConfig 类,如以下代码所示:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${app.protect.authenticated}")
private String[] protectedRoutes;
private final AADB2COidcLoginConfigurer configurer;
public SecurityConfig(AADB2COidcLoginConfigurer configurer) {
this.configurer = configurer;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeRequests()
.antMatchers(protectedRoutes).authenticated() // limit these pages to authenticated users (default: /token_details)
.antMatchers("/**").permitAll() // allow all other routes.
.and()
.apply(configurer)
;
// @formatter:off
}
}
详细信息
- Microsoft 标识平台(针对开发人员的 Microsoft Entra ID)
- Microsoft 身份验证库 (MSAL) 的概述
- 快速入门:将应用程序注册到 Microsoft 标识平台
- 快速入门:配置客户端应用程序以访问 Web API
- 了解 Microsoft Entra ID 应用程序同意体验
- 了解用户同意和管理员同意
- Microsoft Entra ID 中的应用程序和服务主体对象
- 国家云
- MSAL 代码示例
- 适用于 Java 的 Microsoft Entra ID Spring Boot Starter 客户端库
- 适用于 Java 的 Azure Active Directory B2C Spring Boot Starter 客户端库
- 适用于 Java 的 Microsoft 身份验证库 (MSAL4J)
- MSAL4J Wiki
- ID 令牌
- Microsoft 标识平台中的访问令牌
有关 OAuth 2.0 协议如何在此方案和其他方案中工作的详细信息,请参阅 Microsoft Entra ID 的身份验证方案。