你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

教程:创建和发布产品

适用于:所有 API 管理层级

在 Azure API 管理中,一个产品包含一个或多个 API 以及使用配额和使用条款。 发布产品之后,开发人员可订阅该产品,并开始使用产品的 API。

在本教程中,你将了解如何执行以下操作:

  • 创建和发布产品
  • 将 API 添加到产品
  • 访问产品 API

门户中的 API 管理产品

先决条件

创建和发布产品

  1. 登录到 Azure 门户,并导航到 API 管理实例。

  2. 在左侧导航窗格中,选择“产品”>“+ 添加”。

    在 Azure 门户中添加产品

  3. 在“添加产品”窗口中,输入下表中描述的值以创建产品。

    添加产品窗口

    名称 说明
    显示名称 要在开发人员门户中显示的名称。
    说明 提供有关该产品的信息,如其用途、它提供访问权的 API 和其他详细信息。
    State 如果要将产品发布到开发人员门户,请选择“已发布”。 在开发人员可以发现产品中的 API 之前,必须先发布该产品。 默认情况下,新产品是未发布的。
    需要订阅 如果用户需要订阅才能使用产品(产品受保护)并且必须使用订阅密钥才能访问产品的 API,请选择该项。 如果不需要订阅(产品开放),则无需订阅密钥即可访问产品的 API。 请参阅本文后面的访问产品 API
    需要批准 如果希望管理员审查并接受或拒绝此产品的订阅尝试,请选中该项。 如果未选中此项,则会自动批准订阅尝试。
    订阅计数限制 (可选)限制多个同步订阅的计数。
    法律条款 可以包含产品的使用条款,订阅者必须接受这些条款才能使用该产品。
    API 选择一个或多个 API。 还可以在创建产品后添加 API。 有关详细信息,请参阅本文稍后的将 API 添加到产品

    如果产品是开放的(不需要订阅),则只能添加不与另一个开放产品关联的 API。
  4. 选择“创建”以创建新产品。

注意

在配置不需要订阅的产品时,请小心。 此配置可能过于宽松,并且可能会使产品的 API 更容易受到某些 API 安全威胁的影响。

添加更多配置

保存产品后继续对其进行配置。 在 API 管理实例中,从“产品”窗口中选择产品。 添加或更新:

说明
设置 产品元数据和状态
API 与产品关联的 API
策略 应用于产品 API 的策略
访问控制 对开发人员或来宾可见的产品
订阅 产品订阅者

将 API 添加到产品

产品是一个或多个 API 的关联。 可包含许多 API,并通过开发人员门户将其提供给开发人员。 可以在创建产品期间添加一个或多个现有的 API。 之后,也可以通过产品的“设置”页或在创建 API 时将 API 添加到产品。

将 API 添加到现有产品

  1. 在 API 管理实例的左侧导航栏中,选择“产品”。
  2. 选择一个产品,然后选择“API”。
  3. 选择“+ 添加 API”。
  4. 选择一个或多个 API,然后点击“选择”。

将 API 添加到现有产品

访问产品 API

发布产品后,开发人员可以访问 API。 根据产品的配置方式,他们可能需要先订阅产品才能访问该产品。

  • 受保护的产品 - 开发人员必须先订阅受保护的产品才能访问该产品的 API。 订阅时,他们会得到一个订阅密钥,该密钥可以访问该产品中的任何 API。 如果你创建了 API 管理实例,那么你已是管理员,因此默认情况下订阅了每个产品。 有关详细信息,请参阅 Azure API 管理中的订阅

    当客户端使用有效的产品订阅密钥发出 API 请求时,API 管理会处理该请求并允许在产品上下文中进行访问。 可应用为产品配置的策略和访问控制规则。

    提示

    可以通过 REST API 或 PowerShell 命令使用自定义订阅密钥来创建或更新用户对产品的订阅。

  • 开放产品 - 开发人员无需订阅密钥即可访问开放产品的 API。 不过,你可以配置其他机制来保护客户端对 API 的访问,包括 OAuth 2.0客户端证书限制调用方 IP 地址

    注意

    开放产品未列在开发人员门户中供开发人员了解或订阅。 它们仅对“管理员”组可见。 你需要使用另一种机制来通知开发人员无需订阅密钥即可访问的 API。

    当客户端在没有订阅密钥的情况下发出 API 请求时:

    • API 管理会检查 API 是否与开放产品相关联。 一个 API 最多可与一个打开的产品关联。

    • 如果开放产品存在,则它会在该开放产品的上下文中处理请求。 可应用为开放产品配置的策略和访问控制规则。

有关详细信息,请参阅 API 管理在有或没有订阅密钥的情况下如何处理请求

后续步骤

在本教程中,你将了解:

  • 创建和发布产品
  • 将 API 添加到产品
  • 访问产品 API

转到下一教程:

本文将使用 Terraform 创建 Azure API 管理实例、API、产品、组,以及产品与 API 之间和产品与组之间的关联。

使用 Terraform 可以定义、预览和部署云基础结构。 使用 Terraform 时,请使用 HCL 语法来创建配置文件。 利用 HCL 语法,可指定 Azure 这样的云提供程序和构成云基础结构的元素。 创建配置文件后,请创建一个执行计划,利用该计划,可在部署基础结构更改之前先预览这些更改。 验证了更改后,请应用该执行计划以部署基础结构。

  • 指定所需的 Terraform 版本和所需的提供程序。
  • 为资源组名称前缀、资源组位置以及 API 定义导入的内容格式和值定义变量。
  • 创建使用随机名称的资源组。
  • 创建使用随机名称的 API 管理服务。
  • 创建使用随机名称的 API。
  • 在 API 管理服务中创建使用随机名称的产品。
  • 创建使用随机名称的组。
  • 将 API 与产品相关联。
  • 将组与产品相关联。
  • 输出随机值,例如资源组、API 管理服务、API、产品和组的名称。

先决条件

实现 Terraform 代码

注意

本文中的示例代码位于 Azure Terraform GitHub 存储库中。 你可以查看包含当前和以前 Terraform 版本的测试结果的日志文件。

有关更多示例,请参阅演示如何使用 Terraform 管理 Azure 资源的文章和示例代码

  1. 创建用于测试和运行示例 Terraform 代码的目录,并将其设为当前目录。

  2. 创建名为 main.tf 的文件并插入以下代码:

    resource "random_pet" "rg_name" {
      prefix = var.resource_group_name_prefix
    }
    
    resource "azurerm_resource_group" "rg" {
      location = var.resource_group_location
      name     = random_pet.rg_name.id
    }
    
    resource "random_string" "apim_service_name" {
      length  = 8
      lower   = true
      numeric = false
      special = false
      upper   = false
    }
    
    resource "azurerm_api_management" "apim_service" {
      name                = "${random_string.apim_service_name.result}-apim-service"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      publisher_name      = "Example Publisher"
      publisher_email     = "publisher@example.com"
      sku_name            = "Developer_1"
      tags = {
        Environment = "Example"
      }
      policy {
        xml_content = <<XML
        <policies>
          <inbound />
          <backend />
          <outbound />
          <on-error />
        </policies>
    XML
      }
    }
    
    resource "random_string" "api_name" {
      length  = 8
      lower   = true
      numeric = false
      special = false
      upper   = false
    }
    
    resource "random_string" "content_value" {
      length  = 8
      lower   = true
      numeric = false
      special = false
      upper   = false
    }
    
    resource "azurerm_api_management_api" "api" {
      name                = "${random_string.api_name.result}-api"
      resource_group_name = azurerm_resource_group.rg.name
      api_management_name = azurerm_api_management.apim_service.name
      revision            = "1"
      display_name        = "${random_string.api_name.result}-api"
      path                = "example"
      protocols           = ["https", "http"]
      description         = "An example API"
      import {
        content_format = var.open_api_spec_content_format
        content_value  = var.open_api_spec_content_value
      }
    }
    
    resource "random_string" "product_name" {
      length  = 8
      lower   = true
      numeric = false
      special = false
      upper   = false
    }
    
    resource "azurerm_api_management_product" "product" {
      product_id            = "${random_string.product_name.result}-product"
      resource_group_name   = azurerm_resource_group.rg.name
      api_management_name   = azurerm_api_management.apim_service.name
      display_name          = "${random_string.product_name.result}-product"
      subscription_required = true
      approval_required     = false
      published             = true
      description           = "An example Product"
    }
    
    resource "random_string" "group_name" {
      length  = 8
      lower   = true
      numeric = false
      special = false
      upper   = false
    }
    
    resource "azurerm_api_management_group" "group" {
      name                = "${random_string.group_name.result}-group"
      resource_group_name = azurerm_resource_group.rg.name
      api_management_name = azurerm_api_management.apim_service.name
      display_name        = "${random_string.group_name.result}-group"
      description         = "An example group"
    }
    
    resource "azurerm_api_management_product_api" "product_api" {
      resource_group_name = azurerm_resource_group.rg.name
      api_management_name = azurerm_api_management.apim_service.name
      product_id          = azurerm_api_management_product.product.product_id
      api_name            = azurerm_api_management_api.api.name
    }
    
    resource "azurerm_api_management_product_group" "product_group" {
      resource_group_name = azurerm_resource_group.rg.name
      api_management_name = azurerm_api_management.apim_service.name
      product_id          = azurerm_api_management_product.product.product_id
      group_name          = azurerm_api_management_group.group.name
    }
    
  3. 创建名为 outputs.tf 的文件并插入以下代码:

    output "resource_group_name" {
      value = azurerm_resource_group.rg.name
    }
    
    output "apim_service_name" {
      value = azurerm_api_management.apim_service.name
    }
    
    output "api_name" {
      value = azurerm_api_management_api.api.name
    }
    
    output "product_name" {
      value = azurerm_api_management_product.product.product_id
    }
    
    output "group_name" {
      value = azurerm_api_management_group.group.name
    }
    
    output "service_id" {
      description = "The ID of the API Management Service created"
      value       = azurerm_api_management.apim_service.id
    }
    
    output "gateway_url" {
      description = "The URL of the Gateway for the API Management Service"
      value       = azurerm_api_management.apim_service.gateway_url
    }
    
    output "service_public_ip_addresses" {
      description = "The Public IP addresses of the API Management Service"
      value       = azurerm_api_management.apim_service.public_ip_addresses
    }
    
    output "api_outputs" {
      description = "The IDs, state, and version outputs of the APIs created"
      value = {
        id             = azurerm_api_management_api.api.id
        is_current     = azurerm_api_management_api.api.is_current
        is_online      = azurerm_api_management_api.api.is_online
        version        = azurerm_api_management_api.api.version
        version_set_id = azurerm_api_management_api.api.version_set_id
      }
    }
    
    output "product_id" {
      description = "The ID of the Product created"
      value       = azurerm_api_management_product.product.id
    }
    
    output "product_api_id" {
      description = "The ID of the Product/API association created"
      value       = azurerm_api_management_product_api.product_api.id
    }
    
    output "product_group_id" {
      description = "The ID of the Product/Group association created"
      value       = azurerm_api_management_product_group.product_group.id
    }
    
  4. 创建名为 providers.tf 的文件并插入以下代码:

    terraform {
      required_version = ">=1.0"
      
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~>3.0"
        }
        random = {
          source  = "hashicorp/random"
          version = "~>3.0"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
  5. 创建名为 variables.tf 的文件并插入以下代码:

    variable "resource_group_name_prefix" {
      type        = string
      default     = "rg"
      description = "Prefix of the resource group name that's combined with a random ID so name is unique in your Azure subscription."
    }
    
    variable "resource_group_location" {
      type        = string
      default     = "eastus"
      description = "Location of the resource group."
    }
    
    variable "open_api_spec_content_format" {
      type        = string
      default     = "swagger-link-json"
      description = "The format of the content from which the API Definition should be imported. Possible values are: openapi, openapi+json, openapi+json-link, openapi-link, swagger-json, swagger-link-json, wadl-link-json, wadl-xml, wsdl and wsdl-link."
      validation {
        condition     = contains(["openapi", "openapi+json", "openapi+json-link", "openapi-link", "swagger-json", "swagger-link-json", "wadl-link-json", "wadl-xml", "wsdl", "wsdl-link"], var.open_api_spec_content_format)
        error_message = "open_api_spec_content_format must be one of the following: openapi, openapi+json, openapi+json-link, openapi-link, swagger-json, swagger-link-json, wadl-link-json, wadl-xml, wsdl and wsdl-link."
      }
    }
    
    variable "open_api_spec_content_value" {
      type        = string
      default     = "https://petstore3.swagger.io/api/v3/openapi.json"
      description = "The Content from which the API Definition should be imported. When a content_format of *-link-* is specified this must be a URL, otherwise this must be defined inline."
    }
    

初始化 Terraform

运行 terraform init,将 Terraform 部署进行初始化。 此命令将下载管理 Azure 资源所需的 Azure 提供程序。

terraform init -upgrade

要点:

  • 参数 -upgrade 可将必要的提供程序插件升级到符合配置版本约束的最新版本。

创建 Terraform 执行计划

运行 terraform plan 以创建执行计划。

terraform plan -out main.tfplan

要点:

  • terraform plan 命令将创建一个执行计划,但不会执行它。 它会确定创建配置文件中指定的配置需要执行哪些操作。 此模式允许你在对实际资源进行任何更改之前验证执行计划是否符合预期。
  • 使用可选 -out 参数可以为计划指定输出文件。 使用 -out 参数可以确保所查看的计划与所应用的计划完全一致。

应用 Terraform 执行计划

运行 terraform apply,将执行计划应用到云基础结构。

terraform apply main.tfplan

要点:

  • 示例 terraform apply 命令假设你先前运行了 terraform plan -out main.tfplan
  • 如果为 -out 参数指定了不同的文件名,请在对 terraform apply 的调用中使用该相同文件名。
  • 如果未使用 -out 参数,请调用不带任何参数的 terraform apply

验证结果

运行 az apim show 以查看 Azure API 管理:


az apim show --<apim_service_name> --<resource_group_name>

清理资源

不再需要通过 Terraform 创建的资源时,请执行以下步骤:

  1. 运行 terraform plan 并指定 destroy 标志。

    terraform plan -destroy -out main.destroy.tfplan
    

    要点:

    • terraform plan 命令将创建一个执行计划,但不会执行它。 它会确定创建配置文件中指定的配置需要执行哪些操作。 此模式允许你在对实际资源进行任何更改之前验证执行计划是否符合预期。
    • 使用可选 -out 参数可以为计划指定输出文件。 使用 -out 参数可以确保所查看的计划与所应用的计划完全一致。
  2. 运行 terraform apply 以应用执行计划。

    terraform apply main.destroy.tfplan
    

Azure 上的 Terraform 故障排除

排查在 Azure 上使用 Terraform 时遇到的常见问题

后续步骤