适用于 Microsoft Entra 的 Spring Boot 启动器开发人员指南
本文适用于:✅ 版本 4.19.0 ✅ 版本 5.18.0
本文介绍适用于 Microsoft Entra ID 的 Spring Boot Starter 的功能和核心方案。 本文还包括有关常见问题、解决方法和诊断步骤的指导。
构建 Web 应用程序时,标识和访问管理是基础部分。 Azure 提供了一种基于云的标识服务,它与 Azure 生态系统的其余部分深度集成。
虽然 Spring Security 使得可轻松保护基于 Spring 的应用程序,但它不适合特定标识提供者。 适用于 Microsoft Entra ID 的 Spring Boot Starter 可将 Web 应用程序连接到 Microsoft Entra 租户,并使用 Microsoft Entra ID 保护资源服务器。 它使用 Oauth 2.0 协议来保护 Web 应用程序和资源服务器。
可通过以下链接访问初学者包、文档和示例:
先决条件
若要按照本文中的说明操作,你必须具有以下必备组件:
- Azure 订阅;如果没有 Azure 订阅,可激活 MSDN 订阅者权益或注册免费的 Azure 帐户。
- 受支持的 Java 开发工具包 (JDK) 版本 8 或更高版本。 有关详细信息,请参阅Azure 和 Azure Stack 上的 Java 支持。
- Apache Maven 版本 3.0 或更高版本。
- 已向 Microsoft Entra ID 注册的应用程序。 有关详细信息,请参阅快速入门:向 Microsoft 身份平台注册应用程序。
重要
要完成本文中的步骤,需要 Spring Boot 版本 2.5 或更高版本。
核心方案
本指南介绍如何在以下方案中使用 Microsoft Entra 启动器:
允许用户登录的任何基于 Web 的应用程序都是 Web 应用程序。 在验证访问令牌后,资源服务器将接受或拒绝访问。
访问 Web 应用程序
此方案使用 OAuth 2.0 授权代码授予流使用户可通过 Microsoft 帐户登录。
若要在此方案中使用 Microsoft Entra 启动器,请使用以下步骤:
将重定向 URI 设置为 <application-base-uri>/login/oauth2/code/。 例如:http://localhost:8080/login/oauth2/code/
。 请务必包含尾随的 /
。 有关重定向 URI 的详细信息,请查看快速入门:向 Microsoft 标识平台注册应用程序中的添加重定向 URI。
将以下依赖项添加到 pom.xml 文件。
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-active-directory</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
注意
有关如何使用物料清单 (BOM) 管理 Spring Cloud Azure 库版本的详细信息,请参阅 Spring Cloud Azure 开发人员指南的入门部分。
将以下属性添加到 application.yml 文件。 可从你在 Azure 门户中创建的应用注册中获取这些属性的值,如先决条件中所述。
spring:
cloud:
azure:
active-directory:
enabled: true
profile:
tenant-id: <tenant>
credential:
client-id: <your-client-ID>
client-secret: <your-client-secret>
注意
tenant-id
允许的值包括:common
、organizations
、consumers
或租户 ID。 有关这些值的详细信息,请参阅错误 AADSTS50020 - 来自标识提供者的用户帐户不存在于租户中部分中的使用了错误的终结点(个人和组织帐户)部分。 有关转换单租户应用的信息,请参阅将单租户应用转换为 Microsoft Entra ID 上的多租户。
使用默认的安全配置,或者提供自己的配置。
选项 1:使用默认配置。
使用此选项,你无需执行任何操作。 DefaultAadWebSecurityConfigurerAdapter
类会自动配置。
选项 2:提供自定义配置。
若要提供配置,请扩展 AadWebSecurityConfigurerAdapter
类并在 configure(HttpSecurity http)
函数中调用 super.configure(http)
,如下例所示:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AadOAuth2LoginSecurityConfig extends AadWebSecurityConfigurerAdapter {
/**
* Add configuration logic as needed.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.anyRequest().authenticated();
// Do some custom configuration.
}
}
从 Web 应用程序访问资源服务器
若要在此方案中使用 Microsoft Entra 启动器,请使用以下步骤:
如前文所述,设置重定向 URI。
将以下依赖项添加到 pom.xml 文件。
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-active-directory</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
注意
有关如何使用物料清单 (BOM) 管理 Spring Cloud Azure 库版本的详细信息,请参阅 Spring Cloud Azure 开发人员指南的入门部分。
如前文所述,将以下属性添加到 application.yml 文件:
spring:
cloud:
azure:
active-directory:
enabled: true
profile:
tenant-id: <tenant>
credential:
client-id: <your-client-ID>
client-secret: <your-client-secret>
authorization-clients:
graph:
scopes: https://graph.microsoft.com/Analytics.Read, email
注意
tenant-id
允许的值包括:common
、organizations
、consumers
或租户 ID。 有关这些值的详细信息,请参阅错误 AADSTS50020 - 来自标识提供者的用户帐户不存在于租户中部分中的使用了错误的终结点(个人和组织帐户)部分。 有关转换单租户应用的信息,请参阅将单租户应用转换为 Microsoft Entra ID 上的多租户。
此处,graph
是 OAuth2AuthorizedClient
的名称,scopes
是登录时同意所需的范围。
将代码添加到应用程序,如下例所示:
@GetMapping("/graph")
@ResponseBody
public String graph(
@RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient graphClient
) {
// toJsonString() is just a demo.
// oAuth2AuthorizedClient contains access_token. We can use this access_token to access the resource server.
return toJsonString(graphClient);
}
在这里,graph
是在上一步中配置的客户端 ID。 OAuth2AuthorizedClient
包含用于访问资源服务器的访问令牌。
有关演示此方案的完整示例,请参阅 spring-cloud-azure-starter-active-directory 示例:aad-web-application。
保护资源服务器/API
此方案不支持登录,但会通过验证访问令牌来保护服务器。 如果访问令牌有效,则服务器将为请求提供服务。
若要在此方案中使用 Microsoft Entra 启动器,请使用以下步骤:
将以下依赖项添加到 pom.xml 文件。
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-active-directory</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
注意
有关如何使用物料清单 (BOM) 管理 Spring Cloud Azure 库版本的详细信息,请参阅 Spring Cloud Azure 开发人员指南的入门部分。
如前文所述,将以下属性添加到 application.yml 文件:
spring:
cloud:
azure:
active-directory:
enabled: true
credential:
client-id: <your-client-ID>
app-id-uri: <your-app-ID-URI>
可以使用 <your-client-ID> 和 <your-app-ID-URI> 值来验证访问令牌。 可以从 Azure 门户获取 <your-app-ID-URI> 值,如下图所示:
使用默认的安全配置,或者提供自己的配置。
选项 1:使用默认配置。
使用此选项,你无需执行任何操作。 DefaultAadResourceServerWebSecurityConfigurerAdapter
类会自动配置。
选项 2:提供自定义配置。
若要提供配置,请扩展 AadResourceServerWebSecurityConfigurerAdapter
类并在 configure(HttpSecurity http)
函数中调用 super.configure(http)
,如下例所示:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AadOAuth2ResourceServerSecurityConfig extends AadResourceServerWebSecurityConfigurerAdapter {
/**
* Add configuration logic as needed.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
}
}
有关演示此方案的完整示例,请参阅 spring-cloud-azure-starter-active-directory 示例:aad-resource-server。
从某个资源服务器访问其他资源服务器
此方案支持资源服务器访问其他资源服务器。
若要在此方案中使用 Microsoft Entra 启动器,请使用以下步骤:
将以下依赖项添加到 pom.xml 文件。
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-active-directory</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
注意
有关如何使用物料清单 (BOM) 管理 Spring Cloud Azure 库版本的详细信息,请参阅 Spring Cloud Azure 开发人员指南的入门部分。
将以下属性添加到 application.yml 文件:
spring:
cloud:
azure:
active-directory:
enabled: true
profile:
tenant-id: <tenant>
credential:
client-id: <web-API-A-client-ID>
client-secret: <web-API-A-client-secret>
app-id-uri: <web-API-A-app-ID-URI>
authorization-clients:
graph:
scopes:
- https://graph.microsoft.com/User.Read
注意
tenant-id
允许的值包括:common
、organizations
、consumers
或租户 ID。 有关这些值的详细信息,请参阅错误 AADSTS50020 - 来自标识提供者的用户帐户不存在于租户中部分中的使用了错误的终结点(个人和组织帐户)部分。 有关转换单租户应用的信息,请参阅将单租户应用转换为 Microsoft Entra ID 上的多租户。
使用代码中的 @RegisteredOAuth2AuthorizedClient
属性访问相关资源服务器,如下例所示:
@PreAuthorize("hasAuthority('SCOPE_Obo.Graph.Read')")
@GetMapping("call-graph")
public String callGraph(@RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient graph) {
return callMicrosoftGraphMeEndpoint(graph);
}
有关演示此方案的完整示例,请参阅 spring-cloud-azure-starter-active-directory 示例:aad-resource-server-obo。
在一个应用程序中的 Web 应用程序和资源服务器
此方案支持在一个应用程序中访问 Web 应用程序并保护资源服务器/API。
若要在此方案中使用 aad-starter
,请执行以下步骤:
将以下依赖项添加到 pom.xml 文件。
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-active-directory</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
注意
有关如何使用物料清单 (BOM) 管理 Spring Cloud Azure 库版本的详细信息,请参阅 Spring Cloud Azure 开发人员指南的入门部分。
更新 application.yml 文件。 将属性 spring.cloud.azure.active-directory.application-type
设置为 web_application_and_resource_server
,并为每个授权客户端指定授权类型,如下所示。
spring:
cloud:
azure:
active-directory:
enabled: true
profile:
tenant-id: <tenant>
credential:
client-id: <Web-API-C-client-id>
client-secret: <Web-API-C-client-secret>
app-id-uri: <Web-API-C-app-id-url>
application-type: web_application_and_resource_server # This is required.
authorization-clients:
graph:
authorizationGrantType: authorization_code # This is required.
scopes:
- https://graph.microsoft.com/User.Read
- https://graph.microsoft.com/Directory.Read.All
注意
tenant-id
允许的值包括:common
、organizations
、consumers
或租户 ID。 有关这些值的详细信息,请参阅错误 AADSTS50020 - 来自标识提供者的用户帐户不存在于租户中部分中的使用了错误的终结点(个人和组织帐户)部分。 有关转换单租户应用的信息,请参阅将单租户应用转换为 Microsoft Entra ID 上的多租户。
编写 Java 代码,来配置多个 HttpSecurity
实例。
在以下示例代码中,AadWebApplicationAndResourceServerConfig
包含两个安全配置,一个用于资源服务器,另一个用于 Web 应用程序。 高优先级的 ApiWebSecurityConfigurationAdapter
类可配置资源服务器安全适配器。 低优先级的 HtmlWebSecurityConfigurerAdapter
类可配置 Web 应用程序安全适配器。
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AadWebApplicationAndResourceServerConfig {
@Order(1)
@Configuration
public static class ApiWebSecurityConfigurationAdapter extends AadResourceServerWebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
// All the paths that match `/api/**`(configurable) work as the esource server. Other paths work as the web application.
http.antMatcher("/api/**")
.authorizeRequests().anyRequest().authenticated();
}
}
@Configuration
public static class HtmlWebSecurityConfigurerAdapter extends AadWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
// @formatter:off
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();
// @formatter:on
}
}
}
应用程序类型
spring.cloud.azure.active-directory.application-type
属性是可选的,因为依赖项可推断出此值。 只有在使用 web_application_and_resource_server
值时,才必须手动设置属性。
具有依赖项:spring-security-oauth2-client | 具有依赖项:spring-security-oauth2-resource-server | 应用程序类型的有效值 | 默认值 |
---|---|---|---|
是 | 否 | web_application |
web_application |
No | 是 | resource_server |
resource_server |
是 | 是 | web_application ,resource_server ,resource_server_with_obo , web_application_and_resource_server |
resource_server_with_obo |
可配置属性
适用于 Microsoft Entra ID 的 Spring Boot 启动器提供以下属性:
属性 | 说明 |
---|---|
spring.cloud.azure.active-directory.app-id-uri | 供资源服务器用来验证访问令牌中的受众。 仅当受众等于前面所述的 <your-client-ID> 或 <your-app-ID-URI> 值时,访问令牌才有效。 |
spring.cloud.azure.active-directory.authorization-clients | 一个映射,用于配置应用程序将访问的资源 API。 每个项与应用程序将访问的一个资源 API 相对应。 在 Spring 代码中,每个项与一个 OAuth2AuthorizedClient 对象相对应。 |
spring.cloud.azure.active-directory.authorization-clients.<your-client-name>.scopes | 应用程序将获取的资源服务器的 API 权限。 |
spring.cloud.azure.active-directory.authorization-clients.<your-client-name>.authorization-grant-type | 授权客户端的类型。 支持的类型有authorization_code(用于 webapp 的默认类型)、on_behalf_of(用于 resource-server 的默认类型)、client_credentials。 |
spring.cloud.azure.active-directory.application-type | 请参阅应用程序类型。 |
spring.cloud.azure.active-directory.profile.environment.active-directory-endpoint | 授权服务器的基本 URI。 默认值为 https://login.microsoftonline.com/ 。 |
spring.cloud.azure.active-directory.credential.client-id | Microsoft Entra ID 中注册的应用程序 ID。 |
spring.cloud.azure.active-directory.credential.client-secret | 已注册的应用程序的客户端密码。 |
spring.cloud.azure.active-directory.user-group.use-transitive-members | 如果设置为 true,则使用 v1.0/me/transitiveMemberOf 获取组。 否则使用 /v1.0/me/memberOf 。 |
spring.cloud.azure.active-directory.post-logout-redirect-uri | 用于发布注销的重定向 URI。 |
spring.cloud.azure.active-directory.profile.tenant-id | Azure 租户 ID。 tenant-id 允许的值包括:common 、organizations 、consumers 或租户 ID。 |
spring.cloud.azure.active-directory.user-group.allowed-group-names | 如果在 MemberOf Graph API 调用的响应中找到,将被授予权限的预期用户组。 |
spring.cloud.azure.active-directory.user-name-attribute | 指示哪个声明将成为主体的名称。 |
下面的示例演示了如何使用这些属性:
属性示例 1:若要使用 Azure 中国世纪互联而不是 Azure 全球,请执行以下步骤。
将以下属性添加到 application.yml 文件:
spring: cloud: azure: active-directory: enabled: true profile: environment: active-directory-endpoint: https://login.partner.microsoftonline.cn
通过此方法,可使用 Azure 主权或国家云,而不是 Azure 公有云。
属性示例 2:若要使用组名保护 Web 应用程序中的某种方法,请执行以下步骤:
将以下属性添加到 application.yml 文件:
spring:
cloud:
azure:
active-directory:
enabled: true
user-group:
allowed-groups: group1, group2
使用默认的安全配置,或者提供自己的配置。
选项 1:使用默认配置。 使用此选项,你无需执行任何操作。 DefaultAadWebSecurityConfigurerAdapter
类会自动配置。
选项 2:提供自定义配置。 若要提供配置,请扩展 AadWebSecurityConfigurerAdapter
类并在 configure(HttpSecurity http)
函数中调用 super.configure(http)
,如下例所示:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AadOAuth2LoginSecurityConfig extends AadWebSecurityConfigurerAdapter {
/**
* Add configuration logic as needed.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.anyRequest().authenticated();
// Do some custom configuration.
}
}
使用 @PreAuthorize
批注来保护方法,如下例所示:
@Controller
public class RoleController {
@GetMapping("group1")
@ResponseBody
@PreAuthorize("hasRole('ROLE_group1')")
public String group1() {
return "group1 message";
}
@GetMapping("group2")
@ResponseBody
@PreAuthorize("hasRole('ROLE_group2')")
public String group2() {
return "group2 message";
}
@GetMapping("group1Id")
@ResponseBody
@PreAuthorize("hasRole('ROLE_<group1-id>')")
public String group1Id() {
return "group1Id message";
}
@GetMapping("group2Id")
@ResponseBody
@PreAuthorize("hasRole('ROLE_<group2-id>')")
public String group2Id() {
return "group2Id message";
}
}
属性示例 3:若要在访问资源服务器的资源服务器中启用客户端凭据流,请使用以下步骤:
将以下属性添加到 application.yml 文件:
spring:
cloud:
azure:
active-directory:
enabled: true
authorization-clients:
webapiC: # When authorization-grant-type is null, on behalf of flow is used by default
authorization-grant-type: client_credentials
scopes:
- <Web-API-C-app-id-url>/.default
将代码添加到应用程序,如下例所示:
@PreAuthorize("hasAuthority('SCOPE_Obo.WebApiA.ExampleScope')")
@GetMapping("webapiA/webapiC")
public String callClientCredential() {
String body = webClient
.get()
.uri(CUSTOM_LOCAL_READ_ENDPOINT)
.attributes(clientRegistrationId("webapiC"))
.retrieve()
.bodyToMono(String.class)
.block();
LOGGER.info("Response from Client Credential: {}", body);
return "client Credential response " + (null != body ? "success." : "failed.");
}
高级功能
支持在 Web 应用程序中通过 ID 令牌进行访问控制
起动器支持根据 ID 令牌的 roles
声明创建 GrantedAuthority
,来允许使用 ID 令牌在 Web 应用程序中进行授权。 可以使用 Microsoft Entra ID 的 appRoles
功能创建 roles
声明并实现访问控制。
注意
根据 appRoles
生成的 roles
声明用前缀 APPROLE_
进行修饰。
使用 appRoles
作为 roles
声明时,请避免同时将组属性配置为 roles
。 否则,组属性将替代声明来包含组信息而不是 appRoles
。 应避免在清单中进行以下配置:
"optionalClaims": {
"idtoken": [{
"name": "groups",
"additionalProperties": ["emit_as_roles"]
}]
}
为了支持在 Web 应用程序中通过 ID 令牌进行访问控制,请执行以下步骤:
在应用程序中添加应用角色,并将其分配给用户或组。 有关详细信息,请查看如何:在应用程序中添加应用角色并在令牌中接收它们。
将以下 appRoles
配置添加到应用程序的清单中:
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Admin",
"id": "2fa848d0-8054-4e11-8c73-7af5f1171001",
"isEnabled": true,
"description": "Full admin access",
"value": "Admin"
}
]
将代码添加到应用程序,如下例所示:
@GetMapping("Admin")
@ResponseBody
@PreAuthorize("hasAuthority('APPROLE_Admin')")
public String Admin() {
return "Admin message";
}
故障排除
启用客户端日志记录
适用于 Java 的 Azure SDK 提供一致的日志记录案例,有助于排查和解决应用程序错误。 生成的日志将在到达终端之前捕获应用程序的流,帮助查找根本问题。 查看日志记录 wiki,获取有关启用日志记录的指南。
启用 Spring 日志记录
借助 Spring,所有支持的日志记录系统可使用 logging.level.<logger-name>=<level>
在 Spring 环境(例如在 application.properties 中)中设置记录器级别,其中级别为“跟踪”、“调试”、“信息”、“警告”、“错误”、“严重”或“关”。 可使用 logging.level.root
配置根记录器。
以下示例显示了 application.properties 文件中可能的日志记录设置:
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
若要详细了解 Spring 中的日志记录配置,请查看 Spring 文档中的日志记录。
后续步骤
若要了解有关 Spring 和 Azure 的详细信息,请继续访问“Azure 上的 Spring”文档中心。