Поддержка Spring Cloud Azure для Spring Security

В этой статье описывается, как Spring Cloud Azure и Spring Security можно использовать совместно.

Spring Security с идентификатором Microsoft Entra

При разработке веб-приложения управление идентификацией и доступом всегда будет основой.

Azure предлагает отличную платформу для демократизации процесса разработки приложений, так как она предлагает не только облачную службу удостоверений, но и глубокую интеграцию с остальной частью экосистемы Azure.

Spring Security упрощает защиту приложений Spring на основе Spring с помощью мощных абстракций и расширяемых интерфейсов. Однако, каким бы мощным ни был фреймворк Spring, он не предназначен для конкретного поставщика удостоверений.

spring-cloud-azure-starter-active-directory предоставляет оптимальный способ подключения веб-приложения к тенанту Microsoft Entra ID (сокращенно Microsoft Entra ID) и защиты сервера ресурсов с помощью Microsoft Entra ID. Он использует протокол Oauth 2.0 для защиты веб-приложений и серверов ресурсов.

Доступ к веб-приложению

В этом сценарии используется поток предоставления кода авторизации OAuth 2.0 для входа пользователя в систему с помощью учетной записи Microsoft.

Системная схема

Системная схема для автономного веб-приложения.

Создание необходимых ресурсов в Azure

  1. Прочтите Краткое руководство. Регистрация приложения с помощью платформы идентификации Майкрософт.

  2. Создайте регистрацию приложения. Получите AZURE_TENANT_ID, AZURE_CLIENT_ID и AZURE_CLIENT_SECRET.

  3. Задайте для 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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка AADSTS50020: учетная запись пользователя от поставщика удостоверений не существует в арендаторе. Сведения о преобразовании однотенантного приложения см. в статье Преобразование однотенантного приложения в мультитенантное в Microsoft Entra ID.

Теперь запустите приложение и получите доступ к приложению через браузер. Вы будете перенаправлены на страницу входа Майкрософт.

Дополнительные сведения об использовании

Добавление дополнительных конфигураций безопасности
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class AadOAuth2LoginSecurityConfig {

   /**
    * Add configuration logic as needed.
    */
   @Bean
   SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
       http.with(AadWebApplicationHttpSecurityConfigurer.aadWebApplication(), Customizer.withDefaults())
           .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated());
           // Do some custom configuration.
       return http.build();
   }
}
Авторизация доступа по ролям приложений

Создайте необходимые ресурсы в Azure:

Заметка

Если вы хотите использовать управление доступом на основе ролей приложения, нельзя поместить имена групп в утверждение role. Дополнительные сведения см. в разделе Настройка необязательных утверждений групп раздела Предоставление дополнительных утверждений приложению.

Защитите конкретный метод.

class Demo {
   @GetMapping("Admin")
   @ResponseBody
   @PreAuthorize("hasAuthority('APPROLE_Admin')")
   public String admin() {
       return "Admin message";
   }
}
Авторизация доступа по имени группы или идентификатору группы

Добавьте связанные свойства конфигурации.

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 развертывается в следующих национальных облаках:

  • Azure для государственных организаций

  • Azure для Китая (21Vianet)

  • Azure Германия

Ниже приведен пример использования Azure для Китая (21Vianet).

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

Дополнительные сведения см. в разделе Национальные облачные развертывания.

Настройте шаблон URI перенаправления

Разработчики могут настроить URI перенаправления.

Системная схема для URI перенаправления.

Добавьте свойства redirect-uri-template в файл application.yml.

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

Обновите redirect-uri на портале Azure.

Настройка шаблона URI перенаправления.

После установки redirect-uri-templateнеобходимо обновить построитель безопасности:

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class AadOAuth2LoginSecurityConfig {

    /**
     * Add configuration logic as needed.
     */
    @Bean
    public SecurityFilterChain htmlFilterChain(HttpSecurity http) throws Exception {
        // @formatter:off
        http.with(AadWebApplicationHttpSecurityConfigurer.aadWebApplication(), Customizer.withDefaults())
            .oauth2Login(login -> login.loginProcessingUrl("${REDIRECT-URI-TEMPLATE}"))
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
        // @formatter:on
        return http.build();
    }
}

Подключение к идентификатору Microsoft Entra через прокси-сервер

Чтобы подключить Microsoft Entra ID через прокси-сервер, укажите компонент 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.

Веб-приложение, обращающееся к серверам ресурсов

Системная схема

Системная схема для веб-приложения, обращаюющегося к серверам ресурсов.

Создание необходимых ресурсов в Azure

  1. Прочтите Краткое руководство. Регистрация приложения с помощью платформы идентификации Майкрософт.

  2. Создайте регистрацию приложения. Получите AZURE_TENANT_ID, AZURE_CLIENT_ID и AZURE_CLIENT_SECRET.

  3. Задайте для 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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка 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);
    }
}

Теперь запустите приложение и получите доступ к приложению в браузере. Затем вы будете перенаправлены на страницу входа Майкрософт.

Дополнительные сведения об использовании

Поток учетных данных клиента

По умолчанию используется поток кода авторизации; если вы хотите использовать поток учетных данных клиента, вы можете настроить это следующим образом:

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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка AADSTS50020: учетная запись пользователя от поставщика удостоверений не существует в арендаторе. Сведения о преобразовании однотенантного приложения см. в статье Преобразование однотенантного приложения в мультитенантное в Microsoft Entra ID.

Доступ к нескольким серверам ресурсов

В одном веб-приложении можно получить доступ к нескольким серверам ресурсов, настроив следующее:

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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка AADSTS50020: учетная запись пользователя от поставщика удостоверений не существует в арендаторе. Сведения о преобразовании однотенантного приложения см. в статье Преобразование однотенантного приложения в мультитенантное в Microsoft Entra ID.

Затем вы можете использовать OAuth2AuthorizedClient в приложении следующим образом.

public class Demo {
    @GetMapping("/resource-server-1")
    @ResponseBody
    public String graph1(
    @RegisteredOAuth2AuthorizedClient("resource-server-1") OAuth2AuthorizedClient client) {
        return callResourceServer1(client);
    }

    @GetMapping("/resource-server-2")
    @ResponseBody
    public String graph2(
    @RegisteredOAuth2AuthorizedClient("resource-server-2") OAuth2AuthorizedClient client) {
        return callResourceServer2(client);
    }
}

Образцы

Пример проекта: aad-web-application.

Доступ к серверу ресурсов

Этот сценарий не поддерживает вход, просто защищает сервер, проверяя маркер доступа. Если маркер доступа действителен, сервер обслуживает запрос.

Системная схема

Системная схема для автономного использования сервера ресурсов.

Создание необходимых ресурсов в Azure

  1. Прочтите Краткое руководство. Регистрация приложения с помощью платформы идентификации Майкрософт.

  2. Создайте регистрацию приложения. Получите AZURE_CLIENT_ID.

  3. Прочтите Краткое руководство по настройке приложения для предоставления веб-API.

  4. Опубликуйте веб-API с областью с именем Scope-1.

Добавление необходимых зависимостей

<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}

Теперь запустите приложение и получите доступ к веб-API приложения.

  1. Вы получите ответ 401 без токена доступа.

  2. Получите доступ к вашему приложению с помощью токена доступа. Будут проверены следующие утверждения в маркере доступа:

    • iss. Маркер доступа должен быть выдан идентификатором Microsoft Entra.

    • 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 о токенах доступа платформы идентификации Microsoft.

Дополнительные сведения об использовании

Добавление дополнительных конфигураций безопасности
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class AadOAuth2ResourceServerSecurityConfig {

    /**
     * Add configuration logic as needed.
     */
    @Bean
    public SecurityFilterChain htmlFilterChain(HttpSecurity http) throws Exception {
        // @formatter:off
        http.with(AadResourceServerHttpSecurityConfigurer.aadResourceServer(), Customizer.withDefaults())
            .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated());
        // @formatter:on
        return http.build();
    }
}
Проверка разрешений по областям
  1. Создайте необходимые ресурсы в Azure.

  2. Защитите конкретный метод.

    class Demo {
        @GetMapping("scope1")
        @ResponseBody
        @PreAuthorize("hasAuthority('SCOPE_Scope1')")
        public String scope1() {
            return "Congratulations, you can access `scope1` endpoint.";
        }
    }
    

При этом при доступе к конечной точке /scope1 будут проверены следующие утверждения в маркере доступа:

  • scp: значение должно содержать Scope1.
Проверка разрешений по ролям приложений
  1. Создайте необходимые ресурсы в Azure.

  2. Защитите конкретный метод.

    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 (JWT) для проверки подлинности клиента, выполните следующие действия.

  1. См. раздел Регистрация сертификата на платформе удостоверений Майкрософт в статье Учетные данные сертификата для проверки подлинности приложения на платформе удостоверений Майкрософт.
  2. Отправьте сертификат PEM в приложение, зарегистрированное на портале Azure.
  3. Настройте путь к сертификату .PFX или .P12 и пароль к нему.
  4. Добавьте свойство spring.cloud.azure.active-directory.authorization-clients.azure.client-authentication-method=private_key_jwt в конфигурацию клиента, чтобы выполнить аутентификацию через JWT-аутентификацию клиента.

В следующем примере файла конфигурации используется сценарий веб-приложения. Сведения о сертификате настраиваются в глобальных свойствах.

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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка 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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка AADSTS50020: учетная запись пользователя от поставщика удостоверений не существует в арендаторе. Сведения о преобразовании однотенантного приложения см. в статье Преобразование однотенантного приложения в мультитенантное в Microsoft Entra ID.

Подключение к идентификатору Microsoft Entra через прокси-сервер

Чтобы подключить Microsoft Entra ID через прокси-сервер, укажите бин RestTemplateCustomizer. Дополнительные сведения см. в разделе Подключение к идентификатору Microsoft Entra с помощью прокси-.

Образцы

Пример проекта: aad-resource-server.

Сервер ресурсов, посещающий другие серверы ресурсов

Системная схема

Системная схема сервера ресурсов, посещающих другие серверы ресурсов.

Создание необходимых ресурсов в Azure

  1. Прочтите Краткое руководство. Регистрация приложения с помощью платформы идентификации Майкрософт.

  2. Создайте регистрацию приложения. Получите 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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка 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.

Веб-приложение и сервер ресурсов в одном приложении

Создание необходимых ресурсов в Azure

  1. Прочтите Краткое руководство. Регистрация приложения с помощью платформы идентификации Майкрософт.

  2. Создайте регистрацию приложения. Получите 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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка AADSTS50020: учетная запись пользователя от поставщика удостоверений не существует в арендаторе. Сведения о преобразовании однотенантного приложения см. в статье Преобразование однотенантного приложения в мультитенантное в Microsoft Entra ID.

Определите SecurityFilterChain

Настройте несколько экземпляров SecurityFilterChain. AadWebApplicationAndResourceServerConfig содержит две конфигурации цепочки фильтров безопасности для сервера ресурсов и веб-приложения.

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class AadWebApplicationAndResourceServerConfig {

    @Bean
    @Order(1)
    public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
        http.with(AadResourceServerHttpSecurityConfigurer.aadResourceServer(), Customizer.withDefaults())
            // All the paths that match `/api/**`(configurable) work as the resource server. Other paths work as the web application.
            .securityMatcher("/api/**")
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
        return http.build();
    }

    @Bean
    public SecurityFilterChain htmlFilterChain(HttpSecurity http) throws Exception {
        // @formatter:off
        http.with(AadWebApplicationHttpSecurityConfigurer.aadWebApplication(), Customizer.withDefaults())
            .authorizeHttpRequests(auth -> auth.requestMatchers("/login").permitAll().anyRequest().authenticated());
        // @formatter:on
        return http.build();
    }
}

Конфигурация

Настраиваемые свойства spring-cloud-azure-starter-active-directory:

Имя Описание
spring.cloud.azure.active-directory.app-id-uri URI идентификатора приложения, который может использоваться в утверждении "aud" id_token.
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.
spring.cloud.azure.active-directory.credential.client-secret Секрет клиента, используемый при выполнении проверки подлинности субъекта-службы с помощью Azure.
spring.cloud.azure.active-directory.jwk-set-cache-lifespan Срок действия кэшированного набора JWK до истечения срока действия по умолчанию составляет 5 минут.
spring.cloud.azure.active-directory.jwk-set-cache-refresh-time Время обновления кэшированного набора JWK перед истечением срока его действия по умолчанию составляет 5 минут.
spring.cloud.azure.active-directory.jwt-connect-timeout Тайм-аут подключения при обращении к удалённому URL-адресу JWKSet.
spring.cloud.azure.active-directory.jwt-read-timeout Время ожидания чтения для вызова удаленного URL-адреса JWKSet.
spring.cloud.azure.active-directory.jwt-size-limit Ограничение размера в байтах для запроса к удаленному URL-адресу JWKSet.
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. Значения, допустимые для tenant-id: common, organizations, consumersили идентификатор клиента.
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, активируется фильтр аутентификации без сохранения состояния AadAppRoleStatelessAuthenticationFilter. Значение по умолчанию равно false, которое активирует AadAuthenticationFilter.
spring.cloud.azure.active-directory.user-group.allowed-group-ids Идентификаторы группы можно использовать для создания 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
Нет Да resource_server resource_server
Да Да web_application, resource_server, resource_server_with_obo, web_application_and_resource_server resource_server_with_obo

Spring Security с Azure Active Directory B2C

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 URI идентификатора приложения, который может использоваться в качестве значения в утверждении "aud" токена.
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 Базовый URI конечной точки Azure AD B2C.
spring.cloud.azure.active-directory.b2c.credential Сведения о учетных данных Azure AD B2C.
spring.cloud.azure.active-directory.b2c.jwt-connect-timeout Тайм-аут подключения при обращении к удалённому URL-адресу JWKSet.
spring.cloud.azure.active-directory.b2c.jwt-read-timeout Время ожидания чтения для вызова удаленного URL-адреса JWKSet.
spring.cloud.azure.active-directory.b2c.jwt-size-limit Ограничение размера в байтах для запроса к удаленному URL-адресу JWKSet.
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-flows Потоки пользователей.
spring.cloud.azure.active-directory.b2c.user-name-attribute-name Имя атрибута имени пользователя.

Полные конфигурации см. в свойства конфигурации Spring Cloud Azure.

Базовое использование

Веб-приложение — это любое веб-приложение, позволяющее пользователю входить с помощью идентификатора Microsoft Entra ID, в то время как сервер ресурсов будет принимать или запрещать доступ после проверки access_token, полученной из идентификатора Microsoft Entra. В этом руководстве мы рассмотрим 4 сценария:

  1. Доступ к веб-приложению.

  2. Веб-приложение, обращающееся к серверам ресурсов.

  3. Доступ к серверу ресурсов.

  4. Сервер ресурсов, обращаюющийся к другим серверам ресурсов.

Использование 1. Доступ к веб-приложению

В этом сценарии используется поток предоставления кода авторизации OAuth 2.0 для входа пользователя в систему с учетной записью Azure AD B2C.

Выберите Azure AD B2C в меню портала, выберите Приложения, а затем выберите Добавить.

Укажите имя приложения (например, ), добавьте для URL-адреса ответа, запишите идентификатор приложения как , а затем нажмите Сохранить.

Выберите ключи из приложения, выберите Создать ключ, чтобы создать WEB_APP_AZURE_CLIENT_SECRET, а затем нажмите кнопку Сохранить.

Выберите Потоки пользователей слева, а затем выберите Новый поток пользователя.

Выберите зарегистрироваться или в, редактирование профиляи сброс пароля, чтобы создать потоки пользователей соответственно. Укажите имя потока пользователя и атрибуты пользователя и утверждения, а затем выберите Создать.

Выберите разрешения API>Добавить разрешения>API Microsoft, выберите Microsoft Graph, выберите Делегированные разрешения, выберите offline_access и разрешения openid, а затем выберите добавить разрешения для завершения процесса.

Предоставьте согласие администратора для разрешений Graph.

Снимок экрана портала Azure, на котором показан экран разрешений API для приложения с выделенными разрешениями Microsoft 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-springsecurity6</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";
   }
}

Для кода конфигурации безопасности можно обратиться к следующему примеру:

@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(auth -> auth.anyRequest().authenticated())
            .with(configurer, Customizer.withDefaults());
        // @formatter:on
        return http.build();
    }
}

Скопируйте home.html из примера aad-b2c-web-applicationи замените PROFILE_EDIT_USER_FLOW и PASSWORD_RESET_USER_FLOW именами потоков пользователя, которые вы использовали ранее.

Создание и тестирование приложения. Разрешите Webapp работать на порту 8080.

После создания и запуска приложения Maven откройте http://localhost:8080/ в веб-браузере. Вы должны быть перенаправлены на страницу входа.

Выберите ссылку со сценарием входа пользователя. Вы должны быть перенаправлены в Azure AD B2C, чтобы начать процесс аутентификации.

После успешного входа в систему вы увидите пример home page из браузера.

Сценарий использования 2: доступ веб-приложения к серверам ресурсов

Этот сценарий основан на сценарии доступа к веб-приложению и позволяет приложению получать доступ к другим ресурсам. Этот сценарий представляет собой поток предоставления учетных данных клиента OAuth 2.0.

Выберите Azure AD B2C в меню портала, выберите Приложения, а затем выберите Добавить.

Укажите имя приложения (например, ), запишите идентификатор приложения как , а затем выберите Сохранить.

Выберите ключи из приложения, выберите Создать ключ, чтобы создать WEB_API_A_AZURE_CLIENT_SECRET, а затем нажмите кнопку Сохранить.

В области навигации выберите Предоставить API-доступ, а затем выберите Установить. Запишите URI идентификатора приложения в качестве WEB_API_A_APP_ID_URL, а затем выберите Сохранить.

Выберите Manifest в области навигации, а затем вставьте следующий фрагмент JSON в массив appRoles. Запишите 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.

снимок экрана портала Azure с экраном разрешений API приложения.

Добавьте следующую зависимость на основе сценария Доступа к веб-приложению.

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Добавьте следующую конфигурацию на основе сценария Доступа к веб-приложению.

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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка 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.");
   }
}

Код конфигурации безопасности совпадает с доступом к веб-приложению сценария. Добавьте ещё один bean webClient следующим образом:

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

Чтобы написать код java WebApiA, см. раздел Доступ к серверу ресурсов.

Создание и тестирование приложения. Пусть Webapp и WebApiA работают на портах 8080 и 8081 соответственно. Запустите приложения Webapp и WebApiA. Вернитесь на домашнюю страницу после успешного входа. Затем вы можете обратиться к http://localhost:8080/webapp/webApiA, чтобы получить WebApiA-ответ ресурса.

Использование 3. Доступ к серверу ресурсов

Этот сценарий не поддерживает вход. Просто защитите сервер, проверяя маркер доступа, и, если он действителен, он обслуживает запрос.

Чтобы создать разрешение WebApiA, см. раздел Сценарий использования 2: Веб-приложение, обращающееся к серверам ресурсов.

Добавьте разрешение 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или идентификатор клиента. Дополнительные сведения об этих значениях см. в разделе Использована неправильная конечная точка (личные и организационные учетные записи) статьи Ошибка 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.";
   }
}

Для кода конфигурации безопасности можно обратиться к следующему примеру:

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity
public class ResourceServerConfiguration {
    
    @Bean
    public SecurityFilterChain htmlFilterChain(HttpSecurity http) throws Exception {
        JwtAuthenticationConverter authenticationConverter = new JwtAuthenticationConverter();
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix("APPROLE_");
        authenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        // @formatter:off
        http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .oauth2ResourceServer(o -> o.jwt(j -> j.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 разрешений.

снимок экрана портала Azure с экраном разрешений API WebApiA приложения.

На основе доступа к серверу ресурсовдобавьте следующую зависимость в файл 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.";
   }
}

Код конфигурации безопасности такой же, как в сценарии Accessing a resource server; дополнительно добавляется другой компонент webClient, как показано ниже.

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

Создание и тестирование приложения. Пусть WebApiA и WebApiB работают на портах 8081 и 8082 соответственно. Запустите приложения WebApiA и WebApiB, получите маркер доступа для ресурса webApiA и доступ http://localhost:8081/webApiA/webApiB/sample в качестве заголовка авторизации носителя.

Образцы

Дополнительные сведения см. в примерахspring-cloud-azure-starter-active-directory-b2c.