Spring Cloud Azure 支持 for Spring Security
本文适用于: ✔️版本 4.14.0 ✔️ 版本 5.8.0
本文介绍如何结合使用 Spring Cloud Azure 和 Spring Security。
具有 Microsoft Entra ID 的 Spring Security
构建 Web 应用程序时,标识和访问管理始终是基础部分。
Azure 提供了一个实现应用程序开发旅程民主化的绝佳平台,因为它不仅提供云基础标识服务,而且还与 Azure 生态系统的其余部分深度集成。
Spring Security 使用功能强大的抽象和可扩展接口轻松保护基于 Spring 的应用程序。 但是,与 Spring 框架一样强大,它不是针对特定标识提供者定制的。
它提供了 spring-cloud-azure-starter-active-directory
将 Web 应用程序连接到 Microsoft Entra ID(短租户的 Microsoft Entra ID)的最佳方法,并使用 Microsoft Entra ID 保护资源服务器。 它使用 Oauth 2.0 协议来保护 Web 应用程序和资源服务器。
访问 Web 应用程序
此方案使用 OAuth 2.0 授权代码授予 流以使用 Microsoft 帐户登录用户。
系统关系图
在 Azure 中创建所需的资源
创建应用注册。 获取
AZURE_TENANT_ID
和AZURE_CLIENT_ID
AZURE_CLIENT_SECRET
。设置为
redirect URI
APPLICATION_BASE_URI/login/oauth2/code/
- 例如http://localhost:8080/login/oauth2/code/
。 尾部/
是必需的。
添加必需的依赖项
<dependencies>
<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>
</dependencies>
添加所需属性
spring:
cloud:
azure:
active-directory:
enabled: true
profile:
tenant-id: <tenant>
credential:
client-id: ${AZURE_CLIENT_ID}
client-secret: ${AZURE_CLIENT_SECRET}
注意
允许 tenant-id
的值包括: common
、 organizations
、 consumers
或租户 ID。 有关这些值的详细信息,请参阅 错误AADSTS50020的错误终结点(个人和组织帐户) 部分 - 来自标识提供者的用户帐户不存在于租户中。 有关转换单租户应用的信息,请参阅 Microsoft Entra ID 上的“将单租户应用转换为多租户”。
现在,启动应用程序并通过浏览器访问应用程序。 你将重定向到 Microsoft 登录页。
高级用法
添加额外的安全配置
@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
}
}
按应用角色授予访问权限
在 Azure 中创建所需的资源:
读取 向应用程序添加应用角色并在令牌中接收它们。
使用以下参数创建应用角色:
- 显示名称:管理员
- 允许的成员类型:用户/组
- 值:管理员
- 是否要启用此应用角色:是
保护特定方法。
class Demo {
@GetMapping("Admin")
@ResponseBody
@PreAuthorize("hasAuthority('APPROLE_Admin')")
public String admin() {
return "Admin message";
}
}
按组名称或组 ID 授予访问权限
添加相关的配置属性。
spring:
cloud:
azure:
active-directory:
enabled: true
user-group:
allowed-group-names: group1_name_1, group2_name_2
# 1. If allowed-group-ids == all, then all group ID will take effect.
# 2. If "all" is used, we should not configure other group ids.
# 3. "all" is only supported for allowed-group-ids, not supported for allowed-group-names.
allowed-group-ids: group_id_1, group_id_2
保护特定方法。
@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";
}
}
使用国家 Azure 而不是全局 Azure
除了全球 Azure 云之外,Microsoft Entra ID 部署在以下国家/地区云中:
Azure Government
Azure 中国世纪互联
Azure 德国
下面是使用 Azure 中国世纪互联的示例。
spring:
cloud:
azure:
active-directory:
enabled: true
base-uri: https://login.partner.microsoftonline.cn
graph-base-uri: https://microsoftgraph.chinacloudapi.cn
有关详细信息,请参阅 国家云部署。
配置重定向 URI 模板
开发人员可以自定义重定向 URI。
在 application.yml 文件中添加redirect-uri-template
属性。
spring:
cloud:
azure:
active-directory:
enabled: true
redirect-uri-template: ${REDIRECT-URI-TEMPLATE}
在Azure 门户中更新redirect-uri
。
设置 redirect-uri-template
后,需要更新安全生成器:
@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.oauth2Login()
.loginProcessingUrl("${REDIRECT-URI-TEMPLATE}")
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
通过代理连接到 Microsoft Entra ID
若要通过代理连接 Microsoft Entra ID,请提供 RestTemplateCustomizer
类似于以下示例所示的豆类:
@Configuration
class DemoConfiguration {
@Bean
public RestTemplateCustomizer proxyRestTemplateCustomizer() {
return (RestTemplate restTemplate) -> {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_SERVER_HOST, PROXY_SERVER_PORT));
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setProxy(proxy);
restTemplate.setRequestFactory(requestFactory);
};
}
}
示例
示例项目: aad-web-application。
访问资源服务器的 Web 应用程序
系统关系图
在 Azure 中创建所需的资源
创建应用注册。 获取
AZURE_TENANT_ID
和AZURE_CLIENT_ID
AZURE_CLIENT_SECRET
。设置为
redirect URI
APPLICATION_BASE_URI/login/oauth2/code/
,例如http://localhost:8080/login/oauth2/code/
。 尾部/
是必需的。
添加必需的依赖项
<dependencies>
<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>
</dependencies>
添加所需属性
spring:
cloud:
azure:
active-directory:
enabled: true
profile:
tenant-id: <tenant>
credential:
client-id: ${AZURE_CLIENT_ID}
client-secret: ${AZURE_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
表示登录时需要同意的范围。
在应用程序中使用 OAuth2AuthorizedClient
public class Demo {
@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 resource server.
return toJsonString(graphClient);
}
}
现在,启动应用程序并在浏览器中访问应用程序。 然后,你将重定向到 Microsoft 登录页。
高级用法
客户端凭据流
默认流是授权代码流,如果想要使用客户端凭据流,可以如下所示进行配置:
spring:
cloud:
azure:
active-directory:
enabled: true
profile:
tenant-id: <tenant>
credential:
client-id: ${AZURE_CLIENT_ID}
client-secret: ${AZURE_CLIENT_SECRET}
authorization-clients:
graph:
authorization-grant-type: client_credentials # Change type to client_credentials
scopes: https://graph.microsoft.com/Analytics.Read, email
注意
允许 tenant-id
的值包括: common
、 organizations
、 consumers
或租户 ID。 有关这些值的详细信息,请参阅 错误AADSTS50020的错误终结点(个人和组织帐户) 部分 - 来自标识提供者的用户帐户不存在于租户中。 有关转换单租户应用的信息,请参阅 Microsoft Entra ID 上的“将单租户应用转换为多租户”。
访问多个资源服务器
在一个 Web 应用程序中,可以通过配置如下所示来访问多个资源服务器:
spring:
cloud:
azure:
active-directory:
enabled: true
profile:
tenant-id: <tenant>
credential:
client-id: ${AZURE_CLIENT_ID}
client-secret: ${AZURE_CLIENT_SECRET}
authorization-clients:
resource-server-1:
scopes: # Scopes for resource-server-1
resource-server-2:
scopes: # Scopes for resource-server-2
注意
允许 tenant-id
的值包括: common
、 organizations
、 consumers
或租户 ID。 有关这些值的详细信息,请参阅 错误AADSTS50020的错误终结点(个人和组织帐户) 部分 - 来自标识提供者的用户帐户不存在于租户中。 有关转换单租户应用的信息,请参阅 Microsoft Entra ID 上的“将单租户应用转换为多租户”。
然后,可以在如下所示的应用程序中使用OAuth2AuthorizedClient
public class Demo {
@GetMapping("/resource-server-1")
@ResponseBody
public String graph(
@RegisteredOAuth2AuthorizedClient("resource-server-1") OAuth2AuthorizedClient client) {
return callResourceServer1(client);
}
@GetMapping("/resource-server-2")
@ResponseBody
public String graph(
@RegisteredOAuth2AuthorizedClient("resource-server-2") OAuth2AuthorizedClient client) {
return callResourceServer2(client);
}
}
示例
示例项目: aad-web-application。
访问资源服务器
此方案不支持登录,只需通过验证访问令牌来保护服务器。 如果访问令牌有效,则服务器将为请求提供服务。
系统关系图
在 Azure 中创建所需的资源
创建应用注册。 获取
AZURE_CLIENT_ID
。公开名为 <
a0/a0> 范围的 Web API。
添加必需的依赖项
<dependencies>
<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>
</dependencies>
添加所需属性
spring:
cloud:
azure:
active-directory:
enabled: true
credential:
client-id: ${AZURE_CLIENT_ID}
现在启动应用程序并访问应用程序的 Web API。
你将获得 401,而无需访问令牌。
使用访问令牌访问应用程序。 将验证访问令牌中的以下声明:
iss
:访问令牌必须由 Microsoft Entra ID 颁发。nbf
:当前时间不能以前nbf
。exp
:当前时间不能之后exp
。aud
:如果spring.cloud.azure.active-directory.credential.client-id
或spring.cloud.azure.active-directory.credential.app-id-uri
已配置,受众必须等于配置的client-id
或app-id-uri
。 如果未配置这两个属性,则不会验证此声明。
有关访问令牌的详细信息,请参阅有关Microsoft 标识平台访问令牌的 MS 文档。
高级用法
添加额外的安全配置
@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());
}
}
按范围验证权限
在 Azure 中创建所需的资源。
公开名为 <
a0/a0> 范围的 Web API。
保护特定方法。
class Demo { @GetMapping("scope1") @ResponseBody @PreAuthorize("hasAuthority('SCOPE_Scope1')") public String scope1() { return "Congratulations, you can access `scope1` endpoint."; } }
通过执行此操作,访问终结点时,将验证访问 /scope1
令牌中的以下声明:
scp
:该值必须包含Scope1
。
按应用角色验证权限
在 Azure 中创建所需的资源。
读取 向应用程序添加应用角色并在令牌中接收它们。
使用以下参数创建应用角色:
- 显示名称:AppRole1
- 允许的成员类型:用户/组
- 值:AppRole1
- 是否要启用此应用角色:是
保护特定方法。
class Demo { @GetMapping("app-role1") @ResponseBody @PreAuthorize("hasAuthority('APPROLE_AppRole1')") public String appRole1() { return "Congratulations, you can access `app-role1` endpoint."; } }
通过执行此操作,访问终结点时,将验证访问 /app-role1
令牌中的以下声明:
roles
:该值必须包含AppRole1
。
使用 JWT 客户端身份验证
若要使用 JSON Web 令牌(JWT)进行客户端身份验证,请执行以下步骤:
- 请参阅Microsoft 标识平台应用程序身份验证证书凭据的“Microsoft 标识平台注册证书”部分。
- 将 .pem 证书上传到Azure 门户中注册的应用程序。
- 配置证书路径和密码 。PFX 或 .P12 证书。
- 将属性
spring.cloud.azure.active-directory.authorization-clients.azure.client-authentication-method=private_key_jwt
配置添加到要通过 JWT 客户端身份验证进行身份验证的客户端。
以下示例配置文件适用于 Web 应用程序方案。 证书信息在全局属性中配置。
spring:
cloud:
azure:
credential:
client-id: ${AZURE_CLIENT_ID}
client-certificate-path: ${AZURE_CERTIFICATE_PATH}
client-certificate-password: ${AZURE_CERTIFICATE_PASSWORD}
profile:
tenant-id: <tenant>
active-directory:
enabled: true
user-group:
allowed-group-names: group1,group2
allowed-group-ids: <group1-id>,<group2-id>
post-logout-redirect-uri: http://localhost:8080
authorization-clients:
azure:
client-authentication-method: private_key_jwt
arm:
client-authentication-method: private_key_jwt
scopes: https://management.core.windows.net/user_impersonation
graph:
client-authentication-method: private_key_jwt
scopes:
- https://graph.microsoft.com/User.Read
- https://graph.microsoft.com/Directory.Read.All
webapiA:
client-authentication-method: private_key_jwt
scopes:
- ${WEB_API_A_APP_ID_URL}/Obo.WebApiA.ExampleScope
webapiB:
client-authentication-method: private_key_jwt
scopes:
- ${WEB_API_B_APP_ID_URL}/.default
authorization-grant-type: client_credentials
注意
允许 tenant-id
的值包括: common
、 organizations
、 consumers
或租户 ID。 有关这些值的详细信息,请参阅 错误AADSTS50020的错误终结点(个人和组织帐户) 部分 - 来自标识提供者的用户帐户不存在于租户中。 有关转换单租户应用的信息,请参阅 Microsoft Entra ID 上的“将单租户应用转换为多租户”。
还可以在服务属性中 active-directory
配置证书信息,如以下示例所示:
spring:
cloud:
azure:
active-directory:
enabled: true
credential:
client-id: ${AZURE_CLIENT_ID}
client-certificate-path: ${AZURE_CERTIFICATE_PATH}
client-certificate-password: ${AZURE_CERTIFICATE_PASSWORD}
profile:
tenant-id: <tenant>
user-group:
allowed-group-names: group1,group2
allowed-group-ids: <group1-id>,<group2-id>
post-logout-redirect-uri: http://localhost:8080
authorization-clients:
azure:
client-authentication-method: private_key_jwt
arm:
client-authentication-method: private_key_jwt
scopes: https://management.core.windows.net/user_impersonation
graph:
client-authentication-method: private_key_jwt
scopes:
- https://graph.microsoft.com/User.Read
- https://graph.microsoft.com/Directory.Read.All
webapiA:
client-authentication-method: private_key_jwt
scopes:
- ${WEB_API_A_APP_ID_URL}/Obo.WebApiA.ExampleScope
webapiB:
client-authentication-method: private_key_jwt
scopes:
- ${WEB_API_B_APP_ID_URL}/.default
authorization-grant-type: client_credentials
注意
允许 tenant-id
的值包括: common
、 organizations
、 consumers
或租户 ID。 有关这些值的详细信息,请参阅 错误AADSTS50020的错误终结点(个人和组织帐户) 部分 - 来自标识提供者的用户帐户不存在于租户中。 有关转换单租户应用的信息,请参阅 Microsoft Entra ID 上的“将单租户应用转换为多租户”。
通过代理连接到 Microsoft Entra ID
若要通过代理连接 Microsoft Entra ID,请提供 RestTemplateCustomizer
bean。 有关详细信息,请参阅通过代理部分连接到 Microsoft Entra ID。
示例
示例项目: aad-resource-server。
访问其他资源服务器的资源服务器
系统关系图
在 Azure 中创建所需的资源
创建应用注册。 获取
AZURE_TENANT_ID
和AZURE_CLIENT_ID
AZURE_CLIENT_SECRET
。
添加必需的依赖项
<dependencies>
<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>
</dependencies>
添加所需属性
spring:
cloud:
azure:
active-directory:
enabled: true
profile:
tenant-id: <tenant>
credential:
client-id: ${AZURE_CLIENT_ID}
client-secret: ${AZURE_CLIENT_SECRET}
authorization-clients:
graph:
scopes:
- https://graph.microsoft.com/User.Read
注意
允许 tenant-id
的值包括: common
、 organizations
、 consumers
或租户 ID。 有关这些值的详细信息,请参阅 错误AADSTS50020的错误终结点(个人和组织帐户) 部分 - 来自标识提供者的用户帐户不存在于租户中。 有关转换单租户应用的信息,请参阅 Microsoft Entra ID 上的“将单租户应用转换为多租户”。
在应用程序中使用 OAuth2AuthorizedClient
public class SampleController {
@GetMapping("call-graph")
public String callGraph(@RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient graph) {
return callMicrosoftGraphMeEndpoint(graph);
}
}
示例
示例项目: aad-resource-server-obo。
在一个应用程序中的 Web 应用程序和资源服务器
在 Azure 中创建所需的资源
创建应用注册。 获取
AZURE_TENANT_ID
和AZURE_CLIENT_ID
AZURE_CLIENT_SECRET
。
添加必需的依赖项
<dependencies>
<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>
</dependencies>
添加所需属性
将属性 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: ${AZURE_CLIENT_ID}
client-secret: ${AZURE_CLIENT_SECRET}
app-id-uri: ${WEB_API_ID_URI}
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 上的“将单租户应用转换为多租户”。
定义 SecurityFilterChain
配置多个 SecurityFilterChain
实例。 AadWebApplicationAndResourceServerConfig
包含资源服务器和 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 `Resource Server`, other paths work as `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-starter-active-directory 的可配置属性:
名称 | 描述 |
---|---|
spring.cloud.azure.active-directory.app-id-uri | 可在id_token的“aud”声明中使用的应用 ID URI。 |
spring.cloud.azure.active-directory.application-type | Microsoft Entra 应用程序的类型。 |
spring.cloud.azure.active-directory.authenticate-additional-parameters | 将其他参数添加到授权 URL。 |
spring.cloud.azure.active-directory.authorization-clients | OAuth2 授权客户端。 |
spring.cloud.azure.active-directory.credential.client-id | 使用 Azure 执行服务主体身份验证时要使用的客户端 ID。 |
spring.cloud.azure.active-directory.credential.client-secret | 使用 Azure 执行服务主体身份验证时要使用的客户端密码。 |
spring.cloud.azure.active-directory.jwk-set-cache-生命期 | 缓存的 JWK 在过期之前设置的生命周期,默认值为 5 分钟。 |
spring.cloud.azure.active-directory.jwk-set-cache-refresh-time | 缓存的 JWK 在过期之前设置的刷新时间,默认值为 5 分钟。 |
spring.cloud.azure.active-directory.jwt-connect-timeout | JWKSet 远程 URL 调用的连接超时。 |
spring.cloud.azure.active-directory.jwt-read-timeout | JWKSet 远程 URL 调用的读取超时。 |
spring.cloud.azure.active-directory.jwt-size-limit | JWKSet 远程 URL 调用的大小限制(以字节为单位)。 |
spring.cloud.azure.active-directory.post-logout-redirect-uri | 注销后的重定向 URI。 |
spring.cloud.azure.active-directory.profile.cloud-type | 要连接到的 Azure 云的名称。 支持的类型包括:AZURE、AZURE_CHINA、AZURE_GERMANY、AZURE_US_GOVERNMENT、OTHER。 |
spring.cloud.azure.active-directory.profile.environment | Microsoft Entra 终结点的属性。 |
spring.cloud.azure.active-directory.profile.tenant-id | Azure 租户 ID。 允许 tenant-id 的值包括: common 、 organizations 、 consumers 或租户 ID。 |
spring.cloud.azure.active-directory.redirect-uri-template | 重定向终结点:授权服务器用于通过资源所有者用户代理将包含授权凭据的响应返回到客户端。 默认值为 {baseUrl}/login/oauth2/code/ 。 |
spring.cloud.azure.active-directory.resource-server.claim-to-authority-prefix-map | 配置将用于生成 GrantedAuthority 的声明以及 GrantedAuthority 字符串值的前缀。 默认值为:“scp”-> “SCOPE_”、“roles”-> “APPROLE_”。 |
spring.cloud.azure.active-directory.resource-server.principal-claim-name | 在 AuthenticatedPrincipal#getName 中配置访问令牌中返回的声明。 默认值为“sub”。 |
spring.cloud.azure.active-directory.session-stateless | 如果 true 激活无状态身份验证筛选器 AadAppRoleStatlessAuthenticationFilter。 默认值为 false,用于激活 AadAuthenticationFilter。 |
spring.cloud.azure.active-directory.user-group.allowed-group-ids | 组 ID 可用于构造 GrantedAuthority。 |
spring.cloud.azure.active-directory.user-group.allowed-group-names | 组名称可用于构造 GrantedAuthority。 |
spring.cloud.azure.active-directory.user-group.use-transitive-members | 如果为“true”,请使用“v1.0/me/transitiveMemberOf”获取成员。 否则,请使用“v1.0/me/memberOf”。 默认值为 false 。 |
spring.cloud.azure.active-directory.user-name-attribute | 确定要作为主体名称的声明。 |
下面是有关如何使用这些属性的一些示例:
应用程序类型
可以从依赖项推断应用程序类型: spring-security-oauth2-client
或 spring-security-oauth2-resource-server
。 如果推断的值不是所需的值,则可以指定应用程序类型。 下面是有效值和推断值表:
应用程序类型 spring-cloud-azure-starter-active-directory
:
具有依赖项: 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 |
Azure Active Directory B2C 的 Spring Security
Azure Active Directory (Azure AD) B2C 是一项标识管理服务,用于自定义和控制客户在使用应用程序时的注册、登录和管理配置文件的方式。 有了 Azure AD B2C,就可以在执行这些操作的同时保护客户的标识。
依赖项设置
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-active-directory-b2c</artifactId>
</dependency>
</dependencies>
配置
spring-cloud-azure-starter-active-directory-b2c 的可配置属性:
名称 | 描述 |
---|---|
spring.cloud.azure.active-directory.b2c.app-id-uri | 可在令牌的“aud”声明中使用的应用 ID URI。 |
spring.cloud.azure.active-directory.b2c.authenticate-additional-parameters | 身份验证的其他参数。 |
spring.cloud.azure.active-directory.b2c.authorization-clients | 指定客户端配置。 |
spring.cloud.azure.active-directory.b2c.base-uri | Azure AD B2C 终结点基 URI。 |
spring.cloud.azure.active-directory.b2c.credential | Azure AD B2C 凭据信息。 |
spring.cloud.azure.active-directory.b2c.jwt-connect-timeout | JWKSet 远程 URL 调用的连接超时。 |
spring.cloud.azure.active-directory.b2c.jwt-read-timeout | JWKSet 远程 URL 调用的读取超时。 |
spring.cloud.azure.active-directory.b2c.jwt-size-limit | JWKSet 远程 URL 调用的大小限制(以字节为单位)。 |
spring.cloud.azure.active-directory.b2c.login-flow | 指定主登录流密钥。 默认值为 sign-up-or-sign-in 。 |
spring.cloud.azure.active-directory.b2c.logout-success-url | 注销后重定向 URL。 默认值为 http://localhost:8080/login 。 |
spring.cloud.azure.active-directory.b2c.profile | Azure AD B2C 配置文件信息。 |
spring.cloud.azure.active-directory.b2c.reply-url | 获取授权代码后回复 URL。 默认值为 {baseUrl}/login/oauth2/code/ 。 |
spring.cloud.azure.active-directory.b2c.user-flow | 用户流。 |
spring.cloud.azure.active-directory.b2c.user-name-attribute-name | 用户名属性名称。 |
有关完整配置,检查 Spring Cloud Azure 配置属性。
基本用法
Web 应用程序是任何基于 Web 的应用程序,允许用户使用 Microsoft Entra ID 登录,而资源服务器在验证从 Microsoft Entra ID 获取access_token后将接受或拒绝访问。 本指南将介绍 4 种方案:
访问 Web 应用程序。
访问资源服务器的 Web 应用程序。
访问资源服务器。
访问其他资源服务器的资源服务器。
用法 1:访问 Web 应用程序
此方案使用 OAuth 2.0 授权代码授予 流通过 Azure AD B2C 用户登录用户。
从门户菜单中选择 Azure AD B2C,选择“应用程序”,然后选择“添加”。
指定应用程序名称(例如webapp
),为回复 URL 添加http://localhost:8080/login/oauth2/code/
,将应用程序 ID 记录为你的WEB_APP_AZURE_CLIENT_ID
,然后选择“保存”。
从应用程序中选择要生成的WEB_APP_AZURE_CLIENT_SECRET
密钥,然后选择“保存”。
选择 左侧的用户流 ,然后选择“ 新建用户流”。
选择 “注册”或“登录”、“ 配置文件编辑”和 “密码重置 ”以分别创建用户流。 指定用户流名称和用户属性和声明,然后选择“创建”。
选择 API 权限“添加 Microsoft API 权限>>”、“Microsoft Graph”、“委派权限”、“offline_access”和“开放权限”,然后选择“添加权限”以完成该过程。
授予 Graph 权限的管理员许可。
将以下依赖项添加到 pom.xml 文件。
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>azure-spring-boot-starter-active-directory-b2c</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
</dependencies>
使用前面创建的值将属性添加到 application.yml 文件,如以下示例所示:
spring:
cloud:
azure:
active-directory:
b2c:
enabled: true
authenticate-additional-parameters:
domain_hint: xxxxxxxxx # optional
login_hint: xxxxxxxxx # optional
prompt: [login,none,consent] # optional
base-uri: ${BASE_URI}
credential:
client-id: ${WEBAPP_AZURE_CLIENT_ID}
client-secret: ${WEBAPP_AZURE_CLIENT_SECRET}
login-flow: ${LOGIN_USER_FLOW_KEY} # default to sign-up-or-sign-in, will look up the user-flows map with provided key.
logout-success-url: ${LOGOUT_SUCCESS_URL}
user-flows:
${YOUR_USER_FLOW_KEY}: ${USER_FLOW_NAME}
user-name-attribute-name: ${USER_NAME_ATTRIBUTE_NAME}
编写 Java 代码。
对于控制器代码,可以参考以下示例:
@Controller
public class WebController {
private void initializeModel(Model model, OAuth2AuthenticationToken token) {
if (token != null) {
final OAuth2User user = token.getPrincipal();
model.addAllAttributes(user.getAttributes());
model.addAttribute("grant_type", user.getAuthorities());
model.addAttribute("name", user.getName());
}
}
@GetMapping(value = { "/", "/home" })
public String index(Model model, OAuth2AuthenticationToken token) {
initializeModel(model, token);
return "home";
}
}
对于安全配置代码,可以参考以下示例:
@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 {
// @formatter:off
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.apply(configurer);
// @formatter:off
}
}
从 aad-b2c-web-application 示例复制 home.html,并替换PASSWORD_RESET_USER_FLOW
PROFILE_EDIT_USER_FLOW
之前使用的用户流名称。
生成并测试应用。 让我们 Webapp
在端口 8080 上运行。
通过 Maven 生成并启动应用程序后,请在 Web 浏览器中打开 http://localhost:8080/
。 应重定向到登录页。
选择登录用户流的链接。 系统应会重定向到 Azure AD B2C 以启动身份验证过程。
成功登录后,应会看到浏览器中的示例 home page
。
使用情况 2:访问资源服务器的 Web 应用程序
此方案基于 访问 Web 应用程序 方案,允许应用程序访问其他资源。 此方案是 OAuth 2.0 客户端凭据授予 流。
从门户菜单中选择 Azure AD B2C,选择“应用程序”,然后选择“添加”。
指定应用程序名称(例如webApiA
),将应用程序 ID 记录为你的WEB_API_A_AZURE_CLIENT_ID
,然后选择“保存”。
从应用程序中选择要生成的WEB_API_A_AZURE_CLIENT_SECRET
密钥,然后选择“保存”。
从导航窗格中选择 “公开 API ”,然后选择“ 设置”。 将 应用程序 ID URI 记录为你 WEB_API_A_APP_ID_URL
,然后选择“ 保存”。
从导航窗格中选择 “清单 ”,然后将以下 JSON 段粘贴到 appRoles
数组中。 将 应用程序 ID URI 记录为你的 WEB_API_A_APP_ID_URL
,将应用角色的值记录为你的 WEB_API_A_ROLE_VALUE
,然后选择“ 保存”。
{
"allowedMemberTypes": [
"Application"
],
"description": "WebApiA.SampleScope",
"displayName": "WebApiA.SampleScope",
"id": "04989db0-3efe-4db6-b716-ae378517d2b7",
"isEnabled": true,
"value": "WebApiA.SampleScope"
}
选择 API 权限>“添加权限>”我的 API“,选择”WebApiA 应用程序名称“,选择”应用程序权限“,选择”WebApiA.SampleScope“权限,然后选择”添加权限“以完成该过程。
授予 WebApiA 权限的管理员许可。
根据 访问 Web 应用程序 方案添加以下依赖项。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
在访问 Web 应用程序方案的基础上添加以下配置。
spring:
cloud:
azure:
active-directory:
b2c:
enabled: true
base-uri: ${BASE_URI} # Such as: https://xxxxb2c.b2clogin.com
profile:
tenant-id: <tenant>
authorization-clients:
${RESOURCE_SERVER_A_NAME}:
authorization-grant-type: client_credentials
scopes: ${WEB_API_A_APP_ID_URL}/.default
注意
允许 tenant-id
的值包括: common
、 organizations
、 consumers
或租户 ID。 有关这些值的详细信息,请参阅 错误AADSTS50020的错误终结点(个人和组织帐户) 部分 - 来自标识提供者的用户帐户不存在于租户中。 有关转换单租户应用的信息,请参阅 Microsoft Entra ID 上的“将单租户应用转换为多租户”。
Webapp
编写 Java 代码。
对于控制器代码,可以参考以下示例:
class Demo {
/**
* Access to protected data from Webapp to WebApiA through client credential flow. The access token is obtained by webclient, or
* <p>@RegisteredOAuth2AuthorizedClient("webApiA")</p>. In the end, these two approaches will be executed to
* DefaultOAuth2AuthorizedClientManager#authorize method, get the access token.
*
* @return Respond to protected data from WebApi A.
*/
@GetMapping("/webapp/webApiA")
public String callWebApiA() {
String body = webClient
.get()
.uri(LOCAL_WEB_API_A_SAMPLE_ENDPOINT)
.attributes(clientRegistrationId("webApiA"))
.retrieve()
.bodyToMono(String.class)
.block();
LOGGER.info("Call callWebApiA(), request '/webApiA/sample' returned: {}", body);
return "Request '/webApiA/sample'(WebApi A) returned a " + (body != null ? "success." : "failure.");
}
}
安全配置代码与 访问 Web 应用程序 方案中相同。 添加另一个豆, webClient
如下所示:
public class SampleConfiguration {
@Bean
public WebClient webClient(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction function =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(oAuth2AuthorizedClientManager);
return WebClient.builder()
.apply(function.oauth2Configuration())
.build();
}
}
若要编写 WebApiA
Java 代码,请参阅 “访问资源服务器 ”部分。
生成并测试应用。 WebApiA
分别在Webapp
端口 8080 和 8081 上运行。 Webapp
启动和WebApiA
应用程序。 成功登录后返回到主页。 然后 http://localhost:8080/webapp/webApiA
,可以访问以获取 WebApiA
资源响应。
用法 3:访问资源服务器
此方案不支持登录。 只需通过验证访问令牌来保护服务器,如果有效,它将为请求提供服务。
若要生成 WebApiA
权限,请参阅 使用情况 2:访问资源服务器的 Web 应用程序。
为 Web 应用程序添加 WebApiA
权限并授予管理员同意。
将以下依赖项添加到 pom.xml 文件。
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>azure-spring-boot-starter-active-directory-b2c</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
添加以下配置。
spring:
cloud:
azure:
active-directory:
b2c:
enabled: true
base-uri: ${BASE_URI} # Such as: https://xxxxb2c.b2clogin.com
profile:
tenant-id: <tenant>
app-id-uri: ${APP_ID_URI} # If you're using v1.0 token, configure app-id-uri for `aud` verification
credential:
client-id: ${AZURE_CLIENT_ID} # If you're using v2.0 token, configure client-id for `aud` verification
user-flows:
sign-up-or-sign-in: ${SIGN_UP_OR_SIGN_IN_USER_FLOW_NAME}
注意
允许 tenant-id
的值包括: common
、 organizations
、 consumers
或租户 ID。 有关这些值的详细信息,请参阅 错误AADSTS50020的错误终结点(个人和组织帐户) 部分 - 来自标识提供者的用户帐户不存在于租户中。 有关转换单租户应用的信息,请参阅 Microsoft Entra ID 上的“将单租户应用转换为多租户”。
编写 Java 代码。
对于控制器代码,可以参考以下示例:
class Demo {
/**
* webApiA resource api for web app
* @return test content
*/
@PreAuthorize("hasAuthority('APPROLE_WebApiA.SampleScope')")
@GetMapping("/webApiA/sample")
public String webApiASample() {
LOGGER.info("Call webApiASample()");
return "Request '/webApiA/sample'(WebApi A) returned successfully.";
}
}
对于安全配置代码,可以参考以下示例:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> requests.anyRequest().authenticated())
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(new AadJwtBearerTokenAuthenticationConverter());
}
}
生成并测试应用。 让我们 WebApiA
在端口 8081 上运行。 获取资源的访问令牌 webApiA
,然后作为持有者授权标头进行访问 http://localhost:8081/webApiA/sample
。
使用情况 4:访问其他资源服务器的资源服务器
此方案是对访问资源服务器的升级,支持基于 OAuth2 客户端凭据流访问其他应用程序资源。
在参考前面的步骤时,我们将创建应用程序 WebApiB
并公开应用程序权限 WebApiB.SampleScope
。
{
"allowedMemberTypes": [
"Application"
],
"description": "WebApiB.SampleScope",
"displayName": "WebApiB.SampleScope",
"id": "04989db0-3efe-4db6-b716-ae378517d2b7",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "WebApiB.SampleScope"
}
授予管理员权限 WebApiB
许可。
在访问资源服务器的基础上,将以下依赖项添加到 pom.xml 文件。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
根据 访问资源服务器 方案配置添加以下配置。
spring:
cloud:
azure:
active-directory:
b2c:
enabled: true
credential:
client-secret: ${WEB_API_A_AZURE_CLIENT_SECRET}
authorization-clients:
${RESOURCE_SERVER_B_NAME}:
authorization-grant-type: client_credentials
scopes: ${WEB_API_B_APP_ID_URL}/.default
编写 Java 代码。
WebApiA
对于控制器代码,可以参考以下示例:
public class SampleController {
/**
* Access to protected data from WebApiA to WebApiB through client credential flow. The access token is obtained by webclient, or
* <p>@RegisteredOAuth2AuthorizedClient("webApiA")</p>. In the end, these two approaches will be executed to
* DefaultOAuth2AuthorizedClientManager#authorize method, get the access token.
*
* @return Respond to protected data from WebApi B.
*/
@GetMapping("/webApiA/webApiB/sample")
@PreAuthorize("hasAuthority('APPROLE_WebApiA.SampleScope')")
public String callWebApiB() {
String body = webClient
.get()
.uri(LOCAL_WEB_API_B_SAMPLE_ENDPOINT)
.attributes(clientRegistrationId("webApiB"))
.retrieve()
.bodyToMono(String.class)
.block();
LOGGER.info("Call callWebApiB(), request '/webApiB/sample' returned: {}", body);
return "Request 'webApiA/webApiB/sample'(WebApi A) returned a " + (body != null ? "success." : "failure.");
}
}
WebApiB
对于控制器代码,可以参考以下示例:
public class SampleController {
/**
* webApiB resource api for other web application
* @return test content
*/
@PreAuthorize("hasAuthority('APPROLE_WebApiB.SampleScope')")
@GetMapping("/webApiB/sample")
public String webApiBSample() {
LOGGER.info("Call webApiBSample()");
return "Request '/webApiB/sample'(WebApi B) returned successfully.";
}
}
访问资源服务器方案时,安全配置代码相同,添加另一个 beanwebClient
,如下所示
public class SampleConfiguration {
@Bean
public WebClient webClient(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction function =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(oAuth2AuthorizedClientManager);
return WebClient.builder()
.apply(function.oauth2Configuration())
.build();
}
}
生成并测试应用。 WebApiB
分别在WebApiA
端口 8081 和 8082 上运行。 WebApiA
启动和WebApiB
应用程序,获取资源的访问令牌webApiA
,并作为持有者授权标头进行访问http://localhost:8081/webApiA/webApiB/sample
。
示例
有关详细信息,请参阅 spring-cloud-azure-starter-active-directory-b2c 示例。