本文适用于: ✔️版本 4.7.0 ✔️ 版本 5.0.0

本文介绍如何结合使用 Spring Cloud Azure 和 Spring Security。

使用 Azure Active Directory 的 Spring Security

生成 Web 应用程序时,标识和访问管理始终是基础部分。

Azure 提供了一个将应用程序开发过程大众化的绝佳平台,因为它不仅提供基于云的标识服务,还与 Azure 生态系统的其余部分进行深度集成。

Spring Security 通过强大的抽象和可扩展接口可以轻松保护基于 Spring 的应用程序。 但是,虽然 Spring 框架功能强大,但它并非针对特定标识提供者定制。

spring-cloud-azure-starter-active-directory 提供了将 Web 应用程序连接到 Azure Active Directory 的最佳方法, (Azure AD 短) 租户,并使用 Azure AD 保护资源服务器。 它使用 Oauth 2.0 协议来保护 Web 应用程序和资源服务器。

访问 Web 应用程序

此方案使用 OAuth 2.0 授权代码授予 流来使用 Microsoft 帐户登录用户。

系统关系图

在 Azure 中创建所需的资源

  • 阅读 快速入门:向Microsoft 标识平台注册应用程序

  • 创建应用注册。 获取 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:
            profile:
              tenant-id: ${AZURE_TENANT_ID}
            credential:
              client-id: ${AZURE_CLIENT_ID}
              client-secret: ${AZURE_CLIENT_SECRET}
    

    现在,启动应用程序并通过浏览器访问应用程序。 你将重定向到 Microsoft 登录页。

    添加额外的安全配置
    Spring Cloud Azure 4.x Spring Cloud Azure 5.x
    @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
       @Bean
       SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
           http.apply(AadWebApplicationHttpSecurityConfigurer.aadWebApplication())
                   .and()
               .authorizeHttpRequests()
                   .anyRequest().authenticated();
               // Do some custom configuration.
           return http.build();
    
    按应用角色授予访问权限

    在 Azure 中创建所需的资源:

  • 请阅读 将应用角色添加到应用程序并在令牌中接收它们

  • 使用以下参数创建应用角色:

  • 显示名称:管理员
  • 允许的成员类型:用户/组
  • 值:管理员
  • 是否要启用此应用角色:是
  • @PreAuthorize("hasAuthority('APPROLE_Admin')") public String admin() { return "Admin message";
    通过组名称或组 ID 授权访问

    添加相关的配置属性。

    spring:
     cloud:
       azure:
         active-directory:
           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 云外,Azure Active Directory 部署在以下国家/地区云中:

  • Azure Government

  • Azure 中国世纪互联

  • Azure 德国

    下面是使用 Azure 中国世纪互联的示例。

    spring:
      cloud:
        azure:
          active-directory:
            base-uri: https://login.partner.microsoftonline.cn
            graph-base-uri: https://microsoftgraph.chinacloudapi.cn
    

    有关详细信息,请参阅 国家云部署

    配置重定向 URI 模板

    开发人员可以自定义 redirect-uri。

    application.yml 文件中添加redirect-uri-template属性。

    spring:
     cloud:
       azure:
         active-directory:
           redirect-uri-template: ${REDIRECT-URI-TEMPLATE}
    

    在Azure 门户中更新redirect-uri

    设置 redirect-uri-template后,需要更新安全生成器:

    Spring Cloud Azure 4.x Spring Cloud Azure 5.x
    @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();
        @Bean
        public SecurityFilterChain htmlFilterChain(HttpSecurity http) throws Exception {
            // @formatter:off
            http.apply(AadWebApplicationHttpSecurityConfigurer.aadWebApplication())
                    .and()
                .oauth2Login()
                    .loginProcessingUrl("${REDIRECT-URI-TEMPLATE}")
                    .and()
                .authorizeHttpRequests()
                    .anyRequest().authenticated();
            // @formatter:on
            return http.build();
    
    通过代理连接到 Azure AD

    若要通过代理连接 Azure AD,请提供 RestTemplateCustomizer 类似于以下示例所示的 bean:

    @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 中创建所需的资源

  • 阅读快速入门:向Microsoft 标识平台注册应用程序

  • 创建应用注册。 获取 AZURE_TENANT_IDAZURE_CLIENT_IDAZURE_CLIENT_SECRET

  • 设置为 redirect URIAPPLICATION_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:
            profile:
              tenant-id: ${AZURE_TENANT_ID}
            credential:
              client-id: ${AZURE_CLIENT_ID}
              client-secret: ${AZURE_CLIENT_SECRET}
            authorization-clients:
              graph:
                scopes: https://graph.microsoft.com/Analytics.Read, email
    

    此处为 graph 的名称 OAuth2AuthorizedClientscopes 表示登录时需要同意的范围。

    在应用程序中使用 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:
            profile:
              tenant-id: ${AZURE_TENANT_ID}
            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
    
    访问多个资源服务器

    在一个 Web 应用程序中,可以通过如下配置来访问多个资源服务器:

    spring:
      cloud:
        azure:
          active-directory:
            profile:
              tenant-id: ${AZURE_TENANT_ID}
            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
    

    然后,可以在应用程序中使用 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 中创建所需的资源

  • 阅读快速入门:向Microsoft 标识平台注册应用程序

  • 创建应用注册。 获取 AZURE_CLIENT_ID

  • 请阅读 快速入门:将应用程序配置为公开 Web API

  • 使用名为 Scope-1的作用域公开 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:
            credential:
              client-id: ${AZURE_CLIENT_ID}
    

    现在,启动应用程序并访问应用程序的 Web API。

  • 你将在没有访问令牌的情况下获得 401。

  • 使用访问令牌访问应用程序。 将验证访问令牌中的以下声明:

  • iss:访问令牌必须由 Azure AD 颁发。

  • nbf:当前时间不能早于 nbf

  • exp:当前时间不能在 之后 exp

  • aud:如果 spring.cloud.azure.active-directory.credential.client-idspring.cloud.azure.active-directory.credential.app-id-uri 已配置,则受众必须等于配置的 client-idapp-id-uri。 如果未配置这两个属性,则不会验证此声明。

    @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());
    @EnableWebSecurity
    @EnableMethodSecurity
    public class AadOAuth2ResourceServerSecurityConfig {
         * Add configuration logic as needed.
        @Bean
        public SecurityFilterChain htmlFilterChain(HttpSecurity http) throws Exception {
            // @formatter:off
            http.apply(AadResourceServerHttpSecurityConfigurer.aadResourceServer())
                .and()
                .authorizeHttpRequests()
                .anyRequest().authenticated();
            // @formatter:on
            return http.build();
    
    按范围验证权限
  • 在 Azure 中创建所需的资源。

  • 阅读 快速入门:配置应用程序以公开 Web API

  • 使用名为 Scope1的作用域公开 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
  • 是否要启用此应用角色:是
  • @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: ${AZURE_TENANT_ID}
          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
                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
    

    还可以在服务属性中 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: ${AZURE_TENANT_ID}
            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
                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
    
    通过代理连接到 Azure AD

    若要通过代理连接 Azure AD,请提供 RestTemplateCustomizer bean。 有关详细信息,请参阅 通过代理连接到 Azure AD 部分。

    示例项目: aad-resource-server

    访问其他资源服务器的资源服务器

    系统关系图

    在 Azure 中创建所需的资源

  • 阅读快速入门:将应用程序注册到Microsoft 标识平台

  • 创建应用注册。 获取 AZURE_TENANT_IDAZURE_CLIENT_IDAZURE_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:
            profile:
              tenant-id: ${AZURE_TENANT_ID}
            credential:
              client-id: ${AZURE_CLIENT_ID}
              client-secret: ${AZURE_CLIENT_SECRET}
            authorization-clients:
              graph:
                scopes:
                  - https://graph.microsoft.com/User.Read
    

    在应用程序中使用 OAuth2AuthorizedClient

    public class SampleController {
        @GetMapping("call-graph")
        public String callGraph(@RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient graph) {
            return callMicrosoftGraphMeEndpoint(graph);
    

    示例项目: aad-resource-server-obo

    在一个应用程序中的 Web 应用程序和资源服务器

    在 Azure 中创建所需的资源

  • 阅读快速入门:将应用程序注册到Microsoft 标识平台

  • 创建应用注册。 获取 AZURE_TENANT_IDAZURE_CLIENT_IDAZURE_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:
            profile:
              tenant-id: ${AZURE_TENANT_ID}
            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
    

    定义 SecurityFilterChain

    配置多个 SecurityFilterChain 实例。 AadWebApplicationAndResourceServerConfig 包含资源服务器和 Web 应用程序的两个安全筛选器链配置。

    Spring Cloud Azure 4.x Spring Cloud Azure 5.x
    @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
    @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-starter-active-directory 的可配置属性:

    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 Azure Active Directory 终结点的属性。 spring.cloud.azure.active-directory.profile.tenant-id Azure 租户 ID。 spring.cloud.azure.active-directory.redirect-uri-template 重定向终结点:授权服务器用于通过资源所有者 user-agent 将包含授权凭据的响应返回到客户端。 默认值为 {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”。 默认值为 falsespring.cloud.azure.active-directory.user-name-attribute 确定作为主体名称的声明。

    下面是有关如何使用这些属性的一些示例:

    应用程序类型

    可以从依赖项 spring-security-oauth2-clientspring-security-oauth2-resource-server或 推断应用程序类型。 如果推断的值不是所需的值,则可以指定应用程序类型。 下面是有效值和推断值表:

    的应用程序类型 spring-cloud-azure-starter-active-directory

    具有依赖项: spring-security-oauth2-client 具有依赖项: spring-security-oauth2-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.logout-success-url 注销后重定向 URL。 默认值为 http://localhost:8080/loginspring.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 应用程序是允许用户使用 Azure AD 登录的任何基于 Web 的应用程序,而在验证从 Azure AD 获取access_token后,资源服务器将接受或拒绝访问。 本指南将介绍 4 种方案:

  • 访问 Web 应用程序。

  • 访问资源服务器的 Web 应用程序。

  • 访问资源服务器。

  • 访问其他资源服务器的资源服务器。

    用法 1:访问 Web 应用程序

    此方案使用 OAuth 2.0 授权代码授予 流将用户与 Azure AD B2C 用户一起登录。

    从门户菜单中选择 “Azure AD B2C ”,选择“ 应用程序”,然后选择“ 添加”。

    指定应用程序名称 ((如webapp) ),添加http://localhost:8080/login/oauth2/code/回复 URL,将应用程序 ID 记录为 ,WEB_APP_AZURE_CLIENT_ID然后选择“保存”。

    从应用程序中选择 “密钥 ”,选择“ 生成密钥 以生成 WEB_APP_AZURE_CLIENT_SECRET”,然后选择“ 保存”。

    选择左侧的“ 用户流 ”,然后选择“ 新建用户流”。

    选择“注册或登录”、“配置文件编辑”和“密码重置”,分别创建用户流。 指定用户流“名称”和“用户属性和声明”,然后选择“创建”。

    选择“ API 权限>”“添加权限>”“Microsoft API”,选择“ Microsoft Graph”,选择“ 委派的权限”,选择 “offline_accessopenid 权限”,然后选择“ 添加权限” 以完成此过程。

    授予管理员对 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:
             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";
    

    有关安全配置代码,可以参考以下示例:

    Spring Cloud Azure 4.x Spring Cloud Azure 5.x
    @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
    
    @Configuration(proxyBeanMethods = false)
    @EnableWebSecurity
    public class WebSecurityConfiguration {
        private final AadB2cOidcLoginConfigurer configurer;
        public WebSecurityConfiguration(AadB2cOidcLoginConfigurer configurer) {
            this.configurer = configurer;
        @Bean
        SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            // @formatter:off
            http.authorizeHttpRequests()
                    .anyRequest().authenticated()
                    .and()
                .apply(configurer);
            // @formatter:on
            return http.build();
    

    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:
             base-uri: ${BASE_URI}             # Such as: https://xxxxb2c.b2clogin.com
             profile:
               tenant-id: ${AZURE_TENANT_ID}
             authorization-clients:
               ${RESOURCE_SERVER_A_NAME}:
                 authorization-grant-type: client_credentials
                 scopes: ${WEB_API_A_APP_ID_URL}/.default
    

    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 应用程序 方案中的相同。 添加另一个 bean webClient ,如下所示:

    public class SampleConfiguration {
       @Bean
       public WebClient webClient(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
           ServletOAuth2AuthorizedClientExchangeFilterFunction function =
               new ServletOAuth2AuthorizedClientExchangeFilterFunction(oAuth2AuthorizedClientManager);
           return WebClient.builder()
                           .apply(function.oauth2Configuration())
                           .build();
    

    若要编写 WebApiA Java 代码,请参阅 访问资源服务器 部分。

    生成并测试应用。 让 WebappWebApiA 分别在端口 80808081 上运行。 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:
             base-uri: ${BASE_URI}             # Such as: https://xxxxb2c.b2clogin.com
             profile:
               tenant-id: ${AZURE_TENANT_ID}
             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
    

    编写 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.";
    

    根据安全配置代码,可以参考以下示例:

    Spring Cloud Azure 4.x Spring Cloud Azure 5.x
    @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());
        @Bean
        public SecurityFilterChain htmlFilterChain(HttpSecurity http) throws Exception {
            JwtAuthenticationConverter authenticationConverter = new JwtAuthenticationConverter();
            authenticationConverter.setJwtGrantedAuthoritiesConverter(new AadJwtGrantedAuthoritiesConverter());
            // @formatter:off
            http.apply(AadResourceServerHttpSecurityConfigurer.aadResourceServer())
                    .and()
                .oauth2ResourceServer()
                    .jwt()
                        .jwtAuthenticationConverter(authenticationConverter);
            // @formatter:on
            return http.build();
    

    生成并测试应用。 让我们 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:
             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.";
    

    安全配置代码与 访问资源服务器 方案相同,添加另一个 bean webClient ,如下所示

    public class SampleConfiguration {
       @Bean
       public WebClient webClient(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
           ServletOAuth2AuthorizedClientExchangeFilterFunction function =
               new ServletOAuth2AuthorizedClientExchangeFilterFunction(oAuth2AuthorizedClientManager);
           return WebClient.builder()
                           .apply(function.oauth2Configuration())
                           .build();
    

    生成并测试应用。 让 WebApiAWebApiB 分别在端口 80818082 上运行。 WebApiA启动 和 WebApiB 应用程序,获取资源的访问令牌webApiA,并将访问权限http://localhost:8081/webApiA/webApiB/sample作为持有者授权标头。

    有关详细信息,请参阅 spring-cloud-azure-starter-active-directory-b2c 示例

  •