验证 JWT

适用于:所有 API 管理层级

validate-jwt 策略强制要求从指定 HTTP 标头提取、从指定查询参数提取的受支持 JSON Web 令牌 (JWT) 或匹配特定值必须存在且有效。

注意

API 管理还提供了 validate-azure-ad-token 策略用于验证 Microsoft Entra 服务提供的 JWT。

提示

为了帮助你配置此策略,门户提供了基于窗体的引导式编辑器。 详细了解如何设置或编辑 API 管理策略

策略语句

<validate-jwt
    header-name="name of HTTP header containing the token (alternatively, use query-parameter-name or token-value attribute to specify token)"
    query-parameter-name="name of query parameter used to pass the token (alternative, use header-name or token-value attribute to specify token)"
    token-value="expression returning the token as a string (alternatively, use header-name or query-parameter attribute to specify token)"
    failed-validation-httpcode="HTTP status code to return on failure"
    failed-validation-error-message="error message to return on failure"
    require-expiration-time="true | false"
    require-scheme="scheme"
    require-signed-tokens="true | false"
    clock-skew="allowed clock skew in seconds"
    output-token-variable-name="name of a variable to receive a JWT object representing successfully validated token">
  <openid-config url="full URL of the configuration endpoint, for example, https://login.constoso.com/openid-configuration" />
  <issuer-signing-keys>
    <key id="kid-claim" certificate-id="mycertificate" n="modulus" e="exponent">Base64 encoded signing key</key>
    <!-- if there are multiple keys, then add additional key elements -->
  </issuer-signing-keys>
  <decryption-keys>
    <key certificate-id="mycertificate">Base64 encoded signing key</key>
    <!-- if there are multiple keys, then add additional key elements -->
  </decryption-keys>
  <audiences>
    <audience>audience string</audience>
    <!-- if there are multiple possible audiences, then add additional audience elements -->
  </audiences>
  <issuers>
    <issuer>issuer string</issuer>
    <!-- if there are multiple possible issuers, then add additional issuer elements -->
  </issuers>
  <required-claims>
    <claim name="name of the claim as it appears in the token" match="all | any" separator="separator character in a multi-valued claim">
      <value>claim value as it is expected to appear in the token</value>
      <!-- if there is more than one allowed value, then add additional value elements -->
    </claim>
    <!-- if there are multiple possible allowed claim, then add additional claim elements -->
  </required-claims>
</validate-jwt>

属性

属性 说明 需要 默认
header-name 包含令牌的 HTTP 标头的名称。 允许使用策略表达式。 必须指定 header-namequery-parameter-nametoken-value 中的一个。 不适用
query-parameter-name 包含令牌的查询参数的名称。 允许使用策略表达式。 必须指定 header-namequery-parameter-nametoken-value 中的一个。 空值
token-value 一个表达式,返回的字符串包含该令牌。 令牌值中不得返回 Bearer 。 允许使用策略表达式。 必须指定 header-namequery-parameter-nametoken-value 中的一个。 空值
failed-validation-httpcode JWT 未通过验证时会返回的 HTTP 状态代码。 允许使用策略表达式。 401
failed-validation-error-message JWT 未通过验证时会在 HTTP 响应正文中返回的错误消息。 此消息必须对任何特殊字符正确地进行转义。 允许使用策略表达式。 默认错误消息取决于验证问题,例如“JWT 不存在”。
require-expiration-time 布尔值。 指定令牌中是否需要到期声明。 允许使用策略表达式。
require-scheme 令牌方案的名称,例如“Bearer”。 设置了此属性时,策略将确保 Authorization 标头值中存在指定的方案。 允许使用策略表达式。 空值
require-signed-tokens 布尔值。 指定令牌是否需要签名。 允许使用策略表达式。
clock-skew 时间跨度。 用于指定令牌颁发者的系统时钟与 API 管理实例之间的最大预期时间差。 允许使用策略表达式。 0 秒
output-token-variable-name 字符串。 成功进行令牌验证后,将作为 Jwt 类型的对象接收令牌值的上下文变量的名称。 不允许使用策略表达式。 空值

元素

元素 说明 必需
openid-config 添加这些元素中的一个或多个,以指定兼容的 OpenID 配置终结点 URL,以便从该终结点获取签名密钥和颁发者。

每 1 小时从终结点拉取一次包含 JSON Web 密钥集 (JWKS) 的配置并进行缓存。 如果正在验证的令牌引用缓存配置中缺少的验证密钥(使用 kid 声明),或者如果检索失败,则 API 管理最多每 5 分钟从终结点拉取一次。 这些间隔如有更改,恕不另行通知。

响应应符合以下 URL 中定义的规范:https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata

对于 Microsoft Entra ID,请使用在应用注册中配置的 OpenID Connect 元数据终结点,例如:
- v2 https://login.partner.microsoftonline.cn/{tenant-name}/v2.0/.well-known/openid-configuration
- v2 多租户 https://login.partner.microsoftonline.cn/organizations/v2.0/.well-known/openid-configuration
- v1 https://login.partner.microsoftonline.cn/{tenant-name}/.well-known/openid-configuration
- 客户租户(预览版)https://{tenant-name}.ciamlogin.com/{tenant-id}/v2.0/.well-known/openid-configuration

使用你的目录租户名称或 ID(例如 contoso.partner.onmschina.cn)替换 {tenant-name}
issuer-signing-keys key 子元素中 Base64 编码的安全密钥列表,用于验证签名的令牌。 如果存在多个安全密钥,则会对每个密钥进行尝试,直到所有密钥都试完(这种情况表明验证失败),或者直到有一个密钥成功(这对令牌滚动更新十分有用)。

(可选)使用 id 属性指定密钥以匹配 kid 声明。 若要验证使用非对称密钥签名的令牌,可以选择性地使用 certificate-id 属性(其值设置为上传到 API 管理的证书的标识符)指定公钥,或使用该签名密钥的 RSA 模数 n 和指数 e 对采用 Base64url 编码格式指定公钥。
decryption-keys key 子元素中的 Base64 编码密钥列表,用于解密令牌。 如果存在多个安全密钥,则会对每个密钥进行尝试,直到所有密钥都试完(这种情况表明验证失败)或直到有一个密钥成功为止。

若要解密使用非对称密钥加密的令牌,可选择性地使用 certificate-id 属性指定公钥(该属性的值设置为上传到 API 管理的证书的标识符)。
audiences audience 子元素中的可接受且可存在于令牌上的受众声明列表。 如果存在多个受众值,则会对每个值进行尝试,直到有一个值成功(如果所有值都试完却没有一个成功,则表明验证失败)。 必须指定至少一个受众。
issuers issuer 子元素中可接受的、颁发了令牌的主体列表。 如果存在多个颁发者值,则会对每个值进行尝试,直到有一个值成功(如果所有值都试完却没有一个成功,则表明验证失败)。
required-claims claim 子元素中的声明列表,这些声明应存在于令牌上,否则令牌会被视为无效。 如果存在多个声明,则令牌必须根据 match 属性值匹配声明值。

密钥属性

属性 说明 需要 默认
id (仅颁发者签名密钥)字符串。 用于匹配 JWT 中提供的 kid 声明的标识符。 空值
certificate-id 上传到 API 管理的证书实体的标识符,用于指定公钥以验证使用非对称密钥签名的令牌。 空值
n (仅颁发者签名密钥)用于验证使用非对称密钥签名的令牌的颁发者的公钥模数。 必须使用指数 e 的值指定。 不允许使用策略表达式。 空值
e (仅颁发者签名密钥)用于验证使用非对称密钥签名的令牌的颁发者的公钥指数。 必须使用模数 n 的值指定。 不允许使用策略表达式。 空值

声明属性

属性 说明 需要 默认
match claim 元素的 match 属性用于指定:是否策略中的每个声明值都必须存在于令牌中验证才会成功。 可能的值为:

- all - 策略中的每个声明值都必须存在于令牌中验证才会成功。

- any - 至少一个声明值必须存在于令牌中验证才会成功。
all
separator 字符串。 指定要用于从多值声明中提取一组值的分隔符(例如 ",")。 空值

使用情况

使用注意事项

  • validate-jwt 策略要求 exp 注册声明包括在 JWT 令牌中,除非 require-expiration-time 属性已指定并设置为 false
  • 策略支持对称和非对称签名算法:
    • 对称 - 支持以下加密算法:A128CBC-HS256、A192CBC-HS384、A256CBC-HS512。
      • 如果在策略中使用,则必须在策略中以 Base64 编码格式提供内联方式的密钥。
    • 非对称 - 支持以下加密算法:PS256、RS256、RS512、ES256。
      • 如果在策略中使用,则密钥可以通过 OpenID 配置终结点来提供,也可通过提供已上传证书(采用 PFX 格式)的 ID 来提供,该证书包含公钥或公钥的模数-指数对。
  • 若要使用与自承载网关配合使用的一个或多个 OpenID 配置终结点配置策略,OpenID 配置终结点 URL 还必须可供云网关访问。
  • 可以在不同的范围内为不同的目的使用访问限制策略。 例如,可以通过在 API 级别应用 validate-jwt 策略来使用 Microsoft Entra 身份验证保护整个 API,也可以在 API 操作级别应用它并使用 claims 进行更精细的控制。
  • 使用自定义标头 (header-name) 时,将忽略所配置的必需方案 (require-scheme)。 若要使用必需的方案,必须在 Authorization 标头中提供 JWT 令牌。

示例

简单的令牌验证

<validate-jwt header-name="Authorization" require-scheme="Bearer">
    <issuer-signing-keys>
        <key>{{jwt-signing-key}}</key>  <!-- signing key specified as a named value -->
    </issuer-signing-keys>
    <audiences>
        <audience>@(context.Request.OriginalUrl.Host)</audience>  <!-- audience is set to API Management host name -->
    </audiences>
    <issuers>
        <issuer>http://contoso.com/</issuer>
    </issuers>
</validate-jwt>

使用 RSA 证书进行令牌验证

<validate-jwt header-name="Authorization" require-scheme="Bearer">
    <issuer-signing-keys>
        <key certificate-id="my-rsa-cert" />  <!-- signing key specified as certificate ID, enclosed in double-quotes -->
    </issuer-signing-keys>
    <audiences>
        <audience>@(context.Request.OriginalUrl.Host)</audience>  <!-- audience is set to API Management host name -->
    </audiences>
    <issuers>
        <issuer>http://contoso.com/</issuer>
    </issuers>
</validate-jwt>

Microsoft Entra ID 单租户令牌验证

<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
    <openid-config url="https://login.partner.microsoftonline.cn/contoso.partner.onmschina.cn/.well-known/openid-configuration" />
    <audiences>
        <audience>00001111-aaaa-2222-bbbb-3333cccc4444</audience>
    </audiences>
    <required-claims>
        <claim name="id" match="all">
            <value>insert claim here</value>
        </claim>
    </required-claims>
</validate-jwt>

Microsoft Entra ID 客户租户令牌验证

<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
	<openid-config url="https://<tenant-name>.ciamlogin.com/<tenant-id>/v2.0/.well-known/openid-configuration" />
	<required-claims>
		<claim name="azp" match="all">
			<value>insert claim here</value>
		</claim>
	</required-claims>
</validate-jwt>

Azure Active Directory B2C 令牌验证

<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
    <openid-config url="https://login.partner.microsoftonline.cn/tfp/contoso.partner.onmschina.cn/b2c_1_signin/v2.0/.well-known/openid-configuration" />
    <audiences>
        <audience>11112222-bbbb-3333-cccc-4444dddd5555</audience>
    </audiences>
    <required-claims>
        <claim name="id" match="all">
            <value>insert claim here</value>
        </claim>
    </required-claims>
</validate-jwt>

根据令牌声明授予操作访问权限

以下示例演示了如何使用validate-jwt 策略根据令牌声明值授予操作访问权限。

<validate-jwt header-name="Authorization" require-scheme="Bearer" output-token-variable-name="jwt">
    <issuer-signing-keys>
        <key>{{jwt-signing-key}}</key> <!-- signing key is stored in a named value -->
    </issuer-signing-keys>
    <audiences>
        <audience>@(context.Request.OriginalUrl.Host)</audience>
    </audiences>
    <issuers>
        <issuer>contoso.com</issuer>
    </issuers>
    <required-claims>
        <claim name="group" match="any">
            <value>finance</value>
            <value>logistics</value>
        </claim>
    </required-claims>
</validate-jwt>
<choose>
    <when condition="@(context.Request.Method == "POST" && !((Jwt)context.Variables["jwt"]).Claims["group"].Contains("finance"))">
        <return-response>
            <set-status code="403" reason="Forbidden" />
        </return-response>
    </when>
</choose>

后续步骤

有关使用策略的详细信息,请参阅: