本文适用于:✅ 版本 4.19.0 ✅ 版本 5.21.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 的详细信息,请参阅快速入门中的 “添加重定向 URI :向 Microsoft标识平台注册应用程序。
将以下依赖项添加到 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:使用默认配置。
使用此选项时,您不需要做任何操作。 DefaultAadWebSecurityConfiguration
类将自动配置。
选项 2:提供自定义配置。
若要提供配置,请对 HttpSecurity
应用 AadWebApplicationHttpSecurityConfigurer#aadWebApplication
方法,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class AadOAuth2LoginSecurityConfig {
/**
* Add configuration logic as needed.
*/
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.apply(AadWebApplicationHttpSecurityConfigurer.aadWebApplication())
.and()
.authorizeHttpRequests()
.anyRequest().authenticated();
// Do some custom configuration.
return http.build();
}
}
从 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:使用默认配置。
使用此选项时,无需执行任何操作。 DefaultAadResourceServerConfiguration
类是自动配置的。
选项 2:提供自定义配置。
若要提供配置,请对 HttpSecurity
应用 AadResourceServerHttpSecurityConfigurer#aadResourceServer
方法,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class AadOAuth2ResourceServerSecurityConfig {
/**
* Add configuration logic as needed.
*/
@Bean
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http.apply(AadResourceServerHttpSecurityConfigurer.aadResourceServer())
.and()
.authorizeHttpRequests()
.anyRequest().authenticated();
return http.build();
}
}
有关演示此方案的完整示例,请参阅 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 应用程序。 apiFilterChain
bean 具有配置资源服务器安全生成器的高优先级。 htmlFilterChain
bean 的优先级较低,用于配置 Web 应用程序安全生成器。
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class AadWebApplicationAndResourceServerConfig {
@Bean
@Order(1)
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http.apply(AadResourceServerHttpSecurityConfigurer.aadResourceServer())
.and()
// All the paths that match `/api/**`(configurable) work as the resource server. Other paths work as the web application.
.securityMatcher("/api/**")
.authorizeHttpRequests()
.anyRequest().authenticated();
return http.build();
}
@Bean
public SecurityFilterChain htmlFilterChain(HttpSecurity http) throws Exception {
// @formatter:off
http.apply(AadWebApplicationHttpSecurityConfigurer.aadWebApplication())
.and()
.authorizeHttpRequests()
.requestMatchers("/login").permitAll()
.anyRequest().authenticated();
// @formatter:on
return http.build();
}
}
应用程序类型
属性 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 |
否 | 是的 | 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 Starter 提供以下属性:
性能 | 说明 |
---|---|
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 (资源服务器的默认类型)。 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 Global,请使用以下步骤。
将以下属性添加到 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:使用默认配置。 使用此选项时,无需执行任何操作。 DefaultAadWebSecurityConfiguration
类被自动配置。
选项 2:提供自定义配置。 若要提供配置,请为 HttpSecurity
应用 AadWebApplicationHttpSecurityConfigurer#aadWebApplication
方法 ,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class AadOAuth2LoginSecurityConfig {
/**
* Add configuration logic as needed.
*/
@Bean
public SecurityFilterChain htmlFilterChain(HttpSecurity http) throws Exception {
// @formatter:off
http.apply(AadWebApplicationHttpSecurityConfigurer.aadWebApplication())
.and()
.authorizeHttpRequests()
.anyRequest().authenticated();
// @formatter:on
// Do some custom configuration.
return http.build();
}
}
使用@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
,以便在 Web 应用程序中使用 ID 令牌进行授权。 可以使用 appRoles
Microsoft Entra ID 的功能来创建 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 允许所有支持的日志记录系统在 Spring 环境中设置记录器级别,例如在 application.properties 中,通过使用 logging.level.<logger-name>=<level>
,其中 <level>
是 TRACE
、DEBUG
、INFO
、WARN
、ERROR
、FATAL
或 OFF
之一。 可以使用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”文档中心。