使用 Spring Cloud Azure 保护 REST API

本教程介绍如何在 Spring Boot 应用程序中使用 Microsoft Entra ID 启用 REST API 保护。

本文以调查系统为例。 调查系统提供以下 REST API:

  • GET /api/survey/question 用于查看调查。
  • POST /api/survey 用于填写调查。
  • GET /api/survey 用于查看调查结果。

在本文中,通过应用基于角色的访问控制(RBAC)来强制实施以下要求来保护这些 API:

  • GET /api/survey/question 可用于每个请求。
  • 当经过身份验证的用户请求中包含授予 POST /api/survey 范围的访问令牌时,SCOPE_Survey.User 可用。
  • GET /api/survey 可用于经过身份验证的管理员用户请求,这些请求包含具有授权的 SCOPE_Survey.Admin 范围的访问令牌。

先决条件

重要

完成本文中的步骤需要 Spring Boot 2.5 或更高版本。

注册 REST API

使用以下步骤在 Azure 门户中注册 Web API。

  1. 登录 Azure 门户

  2. 如果您有权访问多个租户,请使用目录和订阅筛选器)选择要注册应用程序的租户。

  3. 查找并选择 Microsoft Entra ID

  4. 管理下,选择应用注册>新建注册

  5. 名称 字段中输入应用程序的名称,例如 Api-SurveyService。 应用的用户可能会看到此名称,稍后可以对其进行更改。

  6. 在“支持的帐户类型”下,选择“任何组织目录中的帐户” 。

  7. 选择 注册 以创建应用程序。

  8. 在应用 概述 页上,查找 应用程序(客户端)ID 值,然后将其记录以供以后使用。 需要它来配置此项目的 YAML 配置文件。

  9. 在“管理”下,选择“公开 API>添加范围”。 通过选择“保存并继续”来接受建议的应用程序 ID URI (api://{clientId}),然后输入以下信息:

    • 对于“范围名称”,输入 Survey.User
    • 对于谁能同意,选择管理员和用户
    • 对于管理员同意显示名称,请输入 Access the survey service as a user.
    • 对于管理员同意说明,请输入 Allows the users to write data in survey system.
    • 对于用户同意显示名称,请输入 Access the survey service as a user.
    • 对于用户同意说明,请输入 Allows the users to write data in survey system.
    • 对于“状态”,保留“启用” 。
    • 选择“添加作用域”
  10. 重复上一步以添加另一个作用域。 选择“添加范围”时,请输入以下信息:

    • 对于“范围名称”,输入 Survey.Admin
    • 对于谁能同意,选择管理员和用户
    • 对于管理员同意显示名称,请输入 Access the survey service as a admin.
    • 对于管理员同意说明,请输入 Allows the users to view data in survey system.
    • 对于用户同意显示名称,请输入 Access the survey service as a admin.
    • 对于用户同意说明,请输入 Allows the users to view data in survey system.
    • 对于“状态”,保留“启用” 。
    • 选择“添加作用域”

启用 Spring Cloud Azure Starter Microsoft Entra ID

接下来,使用 Spring Cloud Azure 启用 REST API 保护。

添加安全依赖项

若要安装 Spring Cloud Azure Starter Azure Active Directory 模块,请将以下依赖项添加到 pom.xml 文件:

  • Spring Cloud Azure 材料清单(BOM):

    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>com.azure.spring</groupId>
          <artifactId>spring-cloud-azure-dependencies</artifactId>
          <version>5.22.0</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>
    

    注意

    如果使用 Spring Boot 2.x,请确保将 spring-cloud-azure-dependencies 版本设置为 4.20.0。 应在 <dependencyManagement> 文件的 部分中配置此材料清单(BOM)。 这可确保所有 Spring Cloud Azure 依赖项都使用相同的版本。 有关用于此 BOM 的版本的更多信息,请参阅 哪个版本的 Spring Cloud Azure 我应该使用

  • Spring Cloud Azure Starter Microsoft Entra 项目:

    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-starter-active-directory</artifactId>
    </dependency>
    
  • Spring Boot Starter OAuth2 资源服务器项目:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>
    

授权 HTTP 请求

若要保护调查 REST API,请使用具体的作用域名称添加注释 @PreAuthorize("hasAuthority('SCOPE_Survey.xxx')") 以启用保护,如以下示例所示:

import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;

@RestController
@RequestMapping("/api/survey")
public class SurveyController {

    private static final String QUESTION = "Which sports do you like most?";
    private final Map<LocalDateTime, String> surveys = new LinkedHashMap<>();

    @GetMapping(value = "/question", produces = MediaType.APPLICATION_JSON_VALUE)
    public String question() {
        return QUESTION;
    }

    @PostMapping
    @PreAuthorize("hasAuthority('SCOPE_Survey.User')")
    public String addAnswer(@RequestParam("answer") String answer) {
        if (StringUtils.hasText(answer)) {
            surveys.put(LocalDateTime.now(), answer);
            return "succeeded";
        }
        return "Failed";
    }

    @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    @PreAuthorize("hasAuthority('SCOPE_Survey.Admin')")
    public Map<LocalDateTime, String> list() {
        return surveys;
    }
}

更新 YAML 配置,如以下示例所示:

spring:
  cloud:
    azure:
      active-directory:
        enabled: true
        credential:
          client-id: <your-application-ID-of-Api-SurveyService>
        app-id-uri: <your-application-ID-URI-of-Api-SurveyService>

注意

在 v1.0 令牌中,配置需要 API 的客户端 ID,而在 v2.0 令牌中,可以在请求中使用客户端 ID 或应用程序 ID URI。 可以同时配置这两项以正确完成受众验证。

部署到 Azure Spring Apps

在本地运行 Spring Boot 应用程序后,可以将其移动到生产环境。 Azure Spring Apps 可以轻松地将 Spring Boot 应用程序部署到 Azure,而无需更改任何代码。 该服务管理 Spring 应用程序的基础结构,以便开发人员可以专注于其代码。 Azure Spring Apps 使用全面的监视和诊断、配置管理、服务发现、CI/CD 集成、蓝绿部署等提供生命周期管理。 有关详细信息,请参阅 快速入门:将第一个应用程序部署到 Azure Spring Apps

后续步骤