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

在多租户解决方案中将请求映射到租户

Azure

每当请求到达应用程序时,都需要确定请求所针对的租户。 当具有可能在不同地理区域中托管的特定于租户的基础结构时,需要将传入请求与租户匹配。 随后必须将请求转发到托管该租户资源的物理基础结构,如下所示:

Diagram showing mapping a request from tenants to deployments.

在此页上,我们为技术决策者提供指导,介绍在将请求映射到相应租户时可考虑的方法以及这些方法中涉及的权衡。

注意

此页主要讨论基于 HTTP 的应用程序,如网站和 API。 但是,许多相同的基本原则适用于使用其他通信协议的多租户应用程序。

标识租户的方法

可通过多种方法为传入请求标识租户。

域名

如果使用特定于租户的域或子域名称,则可能可以使用 Host 标头或是包含每个请求的原始主机名的其他 HTTP 标头将请求轻松映射到租户。

但是请考虑以下问题:

  • 用户如何知道要用于访问服务的域名?
  • 你是否具有一个所有租户都可使用的中心入口点(如登陆页面或登录页面)? 如果有,则用户将如何标识需要访问的租户?
  • 你使用哪些其他信息来验证对租户的访问(例如授权令牌)? 授权令牌是否包含特定于租户的域名?

HTTP 请求属性

如果不使用特定于租户的域名,可能仍能够使用 HTTP 请求的各个方面来标识特定请求所针对的租户。 例如,请考虑将租户名称标识为 tailwindtraders 的 HTTP 请求。 这可以使用以下方法进行通信:

  • URL 路径结构,例如 https://app.contoso.com/tailwindtraders/
  • URL 中的查询字符串,例如 https://contoso.com/app?tenant=tailwindtraders
  • 自定义 HTTP 请求标头,例如 X-Tenant-Id: tailwindtraders

重要

在从 Web 浏览器发出 HTTP GET 请求或请求由某些类型的 Web 代理进行处理的情况下,自定义 HTTP 请求标头没有用处。 构建 API 时,或者如果控制发出请求的客户端,并且请求处理链中不包含 Web 代理,应仅对 GET 操作使用自定义 HTTP 标头。

使用此方法时,应考虑以下问题:

  • 用户是否会知道如何访问服务? 例如,如果使用查询字符串标识租户,则中央登陆页面是否需要通过添加查询字符串将用户定向到正确租户?
  • 你是否具有一个所有租户都可使用的中心入口点(如登陆页面或登录页面)? 如果有,则用户将如何标识需要访问的租户?
  • 应用程序是否提供 API? 例如,Web 应用程序是否为单页应用程序 (SPA) 或具有 API 后端的移动应用程序? 如果是,则可能能够使用 API 网关反向代理执行租户映射。

令牌声明

许多应用程序使用基于声明的身份验证和授权协议,例如 OAuth 2.0 或 SAML。 这些协议向客户端提供授权令牌。 令牌包含一组声明,这些声明是有关客户端应用程序或用户的信息片段。 声明可用于传达信息(如用户的电子邮件地址)。 系统因而可以包含用户的电子邮件地址,查找用户到租户映射,然后将请求转发到相应的部署。 或者,甚至可能在标识系统中包含租户映射,并向令牌添加租户 ID 声明。

如果使用声明将请求映射到租户,应考虑以下问题:

  • 是否会使用声明标识租户? 将使用哪个声明?
  • 用户是否可以是多个租户的成员? 如果可能,用户将如何选择要使用的租户?
  • 是否有一个中央身份验证和授权系统用于所有租户? 如果没有,你将如何确保所有令牌颁发机构颁发一致的令牌和声明?

API 密钥

许多应用程序会公开 API。 这些 API 可能供组织内部使用,或供合作伙伴或客户外部使用。 适用于 API 的常见身份验证方法是使用 API 密钥。 API 密钥随每个请求一起提供,可用于查找租户。

可以通过多种方式生成 API 密钥。 一种常见方法是生成加密随机值,并将它与租户 ID 一起存储在查阅表中。 收到请求后,系统会在查阅表中查找 API 密钥,然后将它与租户 ID 匹配。 另一种方法是创建其中包含租户 ID 的有意义的字符串,然后使用 HMAC 等方法对密钥进行数字签名。 处理每个请求时,会验证签名,然后提取租户 ID。

注意

API 密钥不提供高级别安全性,因为它们需要手动进行创建和管理,并且因为它们不包含声明。 更现代且安全的方法是使用具有短生存期令牌的基于声明的授权机制(如 OAuth 2.0 或 OpenID Connect)。

考虑以下问题:

  • 如何生成并颁发 API 密钥?
  • API 客户端如何安全地接收和存储 API 密钥?
  • 是否需要 API 密钥在一段时间后过期? 如何轮换客户端的 API 密钥,而不会导致停机时间?
  • 仅仅依赖客户滚动的 API 密钥是否可为 API 提供足够的安全级别?

注意

API 密钥与密码不同。 API 密钥必须由系统生成,并且它们在所有租户间必须唯一,以便每个 API 密钥可以唯一映射到单个租户。 API 网关(例如 Azure API 管理)可以生成和管理 API 密钥、验证传入请求中的密钥以及将密钥映射到单个 API 订阅者。

客户端证书

客户端证书身份验证(有时称为相互 TLS (mTLS))通常用于服务到服务通信。 客户端证书提供对客户端进行身份验证的安全方法。 与令牌和声明类似,客户端证书提供可用于确定租户的属性。 例如,证书的主题可能包含用户的电子邮件地址(该地址可用于查找租户)。

计划将客户端证书用于租户映射时,请考虑以下事项:

  • 如何安全地颁发并续订服务所信任的客户端证书? 客户端证书的使用可能十分复杂,因为它们需要特殊的基础结构来管理和颁发证书。
  • 客户端证书是仅用于初始登录请求还是附加到对服务进行的所有请求?
  • 当你拥有大量客户端时,颁发和管理证书的过程是否会变得不可管理?
  • 如何实现客户端证书与租户之间的映射?

反向代理

反向代理(也称为应用程序代理)可用于路由 HTTP 请求。 反向代理从流入量终结点接受请求,可以将请求转发到许多后端终结点中的一个。 反向代理对于多租户应用程序非常有用,因为它们可以执行某些请求信息片段之间的映射,从而从应用程序基础结构卸载任务。

许多反向代理可以使用请求的属性确定租户路由。 它们可以检查令牌中的目标域名、URL 路径、查询字符串、HTTP 标头,甚至是声明。

Azure 中使用以下常见反向代理:

  • Azure Front Door 是全局负载均衡器和 Web 应用程序防火墙。 它使用 Microsoft 全球边缘网络来创建快速、安全且可高度缩放的 Web 应用程序。
  • Azure 应用程序网关是托管 Web 流量负载均衡器,部署到与后端服务相同的物理区域中。
  • Azure API 管理针对 API 流量进行了优化。
  • 商业和开放源代码技术(你自己托管)包括 nginx、Traefik 和 HAProxy。

请求验证

应用程序必须验证它接收的任何请求是否针对租户进行了授权,这十分重要。 例如,如果应用程序使用自定义域名将请求映射到租户,则应用程序仍必须检查应用程序收到的每个请求是否针对该租户进行了授权。 尽管请求包含域名或其他租户标识符,但这并不意味着应自动授予访问权限。 使用 OAuth 2.0 时,通过检查受众和范围声明来执行验证。

注意

这是 Microsoft Azure 架构良好的框架中假设零信任安全设计原则的一部分。

实现请求验证时,应考虑以下事项:

  • 如何向针对应用程序的所有请求进行授权? 无论使用哪种方法将请求映射到物理基础结构,都需要对请求进行授权。
  • 使用可信、广泛使用且维护良好的身份验证和授权框架和中间件,而不是自行实现所有验证逻辑。 例如,不生成令牌签名验证逻辑或客户端证书加密库。 而是改用应用程序平台(或已知受信任包)中已经过验证和测试的功能。

性能

租户映射逻辑可能会针对应用程序的每个请求运行。 考虑随着解决方案的增长,租户映射过程将如何缩放。 例如,如果在租户映射期间查询数据库表,数据库是否支持大量负载? 如果租户映射需要对令牌进行解密,那么随着时间推移,计算要求是否会变得过高? 如果流量相当温和,那么这不太可能会影响整体性能。 不过在具有大规模应用程序时,此映射所涉及的开销可能会变得很大。

会话相关性

减少租户映射逻辑性能开销的一种方法是使用会话亲和性。 请考虑仅计算每个会话的第一个请求中的信息,而不是对每个请求执行映射。 然后,应用程序会向客户端提供一个会话 Cookie。 客户端将该会话 Cookie 连同该会话中的所有后续客户端请求一起传递回服务。

注意

Azure 中的许多网络和应用程序服务可以使用会话亲和性发出会话 Cookie 并在本机路由请求。

考虑以下问题:

  • 是否可以使用会话亲和性降低将请求映射到租户的开销?
  • 使用哪些服务将请求路由到每个租户的物理部署? 这些服务是否支持基于 Cookie 的会话亲和性?

租户迁移

租户通常需要移动到新的基础结构(作为租户生命周期的一部分)。 将租户移动到新部署时,它们访问的 HTTP 终结点可能会更改。 发生这种情况时,请考虑需要更新租户映射过程。 可能需要考虑以下事项:

  • 如果应用程序使用域名来映射请求,则迁移时也可能需要 DNS 更改。 DNS 更改可能需要时间来传播到客户端,具体取决于 DNS 服务中 DNS 条目的生存时间。
  • 如果迁移会在迁移过程中更改任何终结点的地址,请考虑暂时将租户的请求重定向到自动刷新的维护页面。

作者

本文由 Microsoft 维护, 它最初是由以下贡献者撰写的。

首席作者:

其他参与者:

若要查看非公开的 LinkedIn 个人资料,请登录到 LinkedIn。

后续步骤

了解在多租户应用程序中使用域名时的注意事项