使用 Microsoft Entra ID 保护 Java Spring Boot 应用
本文演示了一个 Java Spring Boot Web 应用,它使用适用于 Java 的 Microsoft Entra ID Spring Boot Starter 客户端库在 Microsoft Entra ID 租户上登录用户。 它使用 OpenID Connect 协议。
下图显示了应用的拓扑结构:
该客户端应用使用适用于 Java 的 Microsoft Entra ID Spring Boot Starter 客户端库登录用户,并从 Microsoft Entra ID 获取 ID 令牌。 ID 令牌证明用户已通过 Microsoft Entra ID 身份验证,并让用户能够访问受保护的路由。
先决条件
- JDK 版本 17。 本示例是在使用 Java 17 的系统上开发的,但可能与其他版本兼容。
- Maven 3
- 建议在 Visual Studio Code 中运行此示例时使用适用于 Visual Studio Code 的 Java 扩展包。
- Microsoft Entra ID 租户。 有关详细信息,请参阅如何获取 Microsoft Entra ID 租户。
- Microsoft Entra ID 租户中的用户帐户。 本示例不适用于 Microsoft 个人帐户。 因此,如果使用个人帐户登录 Azure 门户,并且目录中没有用户帐户,则现在就需要创建一个。
- 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
或者,导航到 ms-identity-msal-java-samples 存储库,然后将其作为 .zip 文件下载并提取到硬盘驱动器。
重要
为避免 Windows 路径长度限制,建议克隆到驱动器根附近的目录中。
使用 Microsoft Entra ID 租户注册示例应用程序
此示例中有一个项目。 以下各部分将介绍如何使用 Azure 门户注册应用。
选择要在其中创建应用程序的 Microsoft Entra ID 租户
要选择租户,请按以下步骤操作:
登录到 Azure 门户。
如果帐户存在于多个 Microsoft Entra ID 租户中,请在 Azure 门户的角落里选择配置文件,然后选择“切换目录”,将会话更改为所需的 Microsoft Entra ID 租户。
注册应用 (java-spring-webapp-auth-auth)
要注册应用,请按照以下步骤操作:
导航到 Azure 门户,然后选择 Microsoft Entra ID。
在导航窗格中选择“应用注册”,然后选择“新注册”。
在出现的“注册应用程序”页面中,输入以下应用程序注册的信息:
- 在“名称”部分中,输入一个有意义的应用名称,以便向应用用户显示,例如
java-spring-webapp-auth
。 - 在“支持的帐户类型”下,选择“仅此组织目录中的帐户”。
- 在“重定向 URI(可选)”部分的组合框中选择“Web”,然后输入以下重定向 URI:
http://localhost:8080/login/oauth2/code/
。
- 在“名称”部分中,输入一个有意义的应用名称,以便向应用用户显示,例如
选择“注册”以创建应用程序。
在应用的注册页面上,找到并复制“应用程序(客户端) ID”值,以供稍后使用。 可以在应用程序的一个或多个配置文件中使用此值。
在应用的注册页面上,选择导航窗格中的“证书和机密”,打开可生成机密和上传证书的页面。
在“客户端密码”部分中,选择“新建客户端密码”。
键入描述,例如“应用机密”。
从可用期限中选择一个:“1 年内”、“2 年内”或“永不过期”。
选择 添加 。 此时将显示生成的值。
复制并保存生成的值,以供在之后的步骤中使用。 代码的配置文件需要使用此值。 此值不会再显示,也无法通过任何其他方式获取。 因此,在导航到任何其他屏幕或窗格之前,请务必从 Azure 门户保存该值。
配置应用 (java-spring-webapp-auth-auth) 以使用应用注册
按照以下步骤来配置应用:
注意
在以下步骤中,ClientID
与 Application ID
或 AppId
相同。
在 IDE 中打开项目。
打开 src\main\resources\application.yml 文件。
找到占位符
Enter_Your_Tenant_ID_Here
,用你的 Microsoft Entra 租户 ID 替换现有值。找到占位符
Enter_Your_Client_ID_Here
,然后用从 Azure 门户复制的java-spring-webapp-auth
应用的应用程序 ID 或clientId
替换现有值。找到占位符
Enter_Your_Client_Secret_Here
,然后用从 Azure 门户复制的创建java-spring-webapp-auth
时保存的值替换现有值。
运行示例
以下各部分将展示如何将示例部署到 Azure 容器应用。
先决条件
- 一个 Azure 帐户。 如果没有帐户,请创建一个免费帐户。 需要拥有 Azure 订阅的“参与者”或“所有者”权限才能继续操作。 有关详细信息,请参阅使用 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 容器应用实例“概述”页面的导航窗格中,选择“日志”以检查应用的日志。
探索示例
按照以下步骤来探索示例:
- 注意屏幕中央显示的登录或退出状态。
- 选择角落里的上下文相关按钮。 首次运行应用时,此按钮显示“登录”。 或者,选择令牌详细信息。 由于此页面受保护并需要身份验证,因此你会被自动重定向到登录页面。
- 在下一页上,按照说明使用 Microsoft Entra ID 租户中的帐户登录。
- 在同意屏幕上,请注意正在请求的范围。
- 成功完成登录流程后,你将被重定向到主页(显示“登录状态”)或“令牌详细信息”页面,这取决于哪个按钮触发了你的登录流。
- 请注意,上下文相关按钮现在显示“注销”并显示你的用户名。
- 如果是在主页上,请选择“ID 令牌详细信息”,以便查看 ID 令牌的一些已解码声明。
- 使用角落的按钮注销。状态页面会显示新的状态。
关于代码
此示例演示了如何使用适用于 Java 的 Microsoft Entra ID Spring Boot Starter 客户端库将用户登录到 Microsoft Entra ID 租户。 此示例还使用了 Spring Oauth2 Client 和 Spring Web Boot Starter。 该示例使用从 Microsoft Entra ID 获取的 ID 令牌中的声明来显示已登录用户的详细信息。
目录
下表列出了示例项目文件夹的内容:
文件/文件夹 | 说明 |
---|---|
pom.xml | 应用程序依赖项。 |
src/main/resources/templates/ | 适用于 UI 的 Thymeleaf 模板。 |
src/main/resources/application.yml | 应用程序和 Microsoft Entra ID 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();
}
登录和注销链接
对于登录,应用会向 Microsoft Entra ID Spring Boot Starter Java 客户端库自动配置的 Microsoft Entra ID 登录终结点发出请求,如下例所示:
<a class="btn btn-success" href="/oauth2/authorization/azure">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>
使用 AADWebSecurityConfigurerAdapter 保护路由
默认情况下,应用会保护“ID 令牌详细信息”页面,只有已登录的用户才能访问该页面。 应用通过使用 application.yml 文件中的 app.protect.authenticated
属性来配置这些路由。 要配置应用的特定要求,请将 AadWebApplicationHttpSecurityConfigurer#aadWebApplication
方法应用于 HttpSecurity
实例。 例如,请参阅此应用程序的 SecurityConfig 类,如以下代码所示:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Value("${app.protect.authenticated}")
private String[] allowedOrigins;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http.apply(AadWebApplicationHttpSecurityConfigurer.aadWebApplication())
.and()
.authorizeHttpRequests(auth -> auth
.requestMatchers(allowedOrigins).authenticated()
.anyRequest().permitAll()
);
// @formatter:on
return http.build();
}
@Bean
@RequestScope
public ServletUriComponentsBuilder urlBuilder() {
return ServletUriComponentsBuilder.fromCurrentRequest();
}
}
详细信息
- Microsoft 标识平台(针对开发人员的 Microsoft Entra ID)
- Microsoft 身份验证库 (MSAL) 的概述
- 快速入门:将应用程序注册到 Microsoft 标识平台
- 快速入门:配置客户端应用程序以访问 Web API
- 了解 Microsoft Entra ID 应用程序同意体验
- 了解用户同意和管理员同意
- Microsoft Entra ID 中的应用程序和服务主体对象
- 国家云
- MSAL 代码示例
- 适用于 Java 的 Microsoft Entra ID Spring Boot Starter 客户端库
- 适用于 Java 的 Microsoft 身份验证库 (MSAL4J)
- MSAL4J Wiki
- ID 令牌
- Microsoft 标识平台中的访问令牌
有关 OAuth 2.0 协议如何在此方案和其他方案中工作的详细信息,请参阅 Microsoft Entra ID 的身份验证方案。