验证 JSON Web 令牌 - Amazon Cognito
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

验证 JSON Web 令牌

这些步骤描述了验证用户池 JSON Web 令牌(JWT)的过程。

先决条件

您的库、开发工具包或软件框架可能已处理本部分中的任务。 Amazon 软件开发工具包为应用程序中的 Amazon Cognito 用户池令牌处理和管理提供了工具。 Amazon Amplify 包括检索和刷新 Amazon Cognito 令牌的功能。

有关更多信息,请参阅以下页面。

许多库可用于解码和验证 JSON Web 令牌 (JWT)。如果您要手动处理用于服务器端 API 处理的令牌,或者您使用的是其他编程语言,则这些库可以为您提供帮助。请参阅用于处理 JWT 令牌库的 OpenID Foundation 列表

使用验证令牌 aws-jwt-verify

在 Node.js 应用程序中, Amazon 建议使用该aws-jwt-verify库来验证用户传递给应用程序的令牌中的参数。使用 aws-jwt-verify,您可以使用要为一个或多个用户群体验证的声明值填充 CognitoJwtVerifier。它可以检查的一些值包括以下内容。

有关您可以在 Node.js 应用程序或 Amazon Lambda 授权方中使用的更多信息和示例代码,请参阅aws-jwt-verify上 GitHub的。

了解和检查令牌

在将令牌检查与应用程序集成之前,请考虑 Amazon Cognito 如何组装 JWT。从用户群体中检索示例令牌。解码并详细检查它们,以了解它们的特征,并确定要验证的内容和时间。例如,您可能希望检查一个场景中的组成员资格,而在另一个场景中,您可能想要检查范围。

以下部分描述在准备应用程序时手动检查 Amazon Cognito JWT 的过程。

确认 JWT 的结构

JSON Web 令牌 (JWT) 包括三个部分,各部分之间有一个 .(圆点)分隔符。

标题

Amazon Cognito 用来对令牌进行签名的密钥 ID kid 和 RSA 算法 alg。Amazon Cognito 使用 alg (RS256) 对令牌进行签名。

有效负载

令牌声明。在 ID 令牌中,声明包括用户属性和有关用户群体 iss 和应用程序客户端 aud 的信息。在访问令牌中,有效负载包括范围、组成员资格、用户群体身份 (iss) 和应用程序客户端 (client_id)。

签名

签名不是像标头和有效负载那样的可解码 base64。它是一个 RSA256 标识符,派生自签名密钥和参数(您可以在 JWKS URI 上观察到)。

标头和有效负载是以 base64 编码的 JSON。您可以通过解码为起始字符 eyJ 的开头字符 { 来识别它们。如果用户向您的应用程序提供了以 base64 编码的 JWT,但其格式不是 [JSON Header].[JSON Payload].[Signature],则它不是有效的 Amazon Cognito 令牌,您可以将其丢弃。

验证 JWT

JWT 签名是标头和负载的哈希组合。Amazon Cognito 为每个用户池生成两对 RSA 加密密钥。一个私有密钥对访问令牌进行签名,另一个私有密钥对 ID 令牌进行签名。

验证 JWT 令牌的签名
  1. 解码 ID 令牌。

    OpenID Foundation 还维护用于处理 JWT 令牌的库列表

    您还可以使用 Amazon Lambda 解码用户池 JWT。有关更多信息,请参阅使用解码和验证 Amazon Cognito J WT 令牌。 Amazon Lambda

  2. 将本地密钥 ID (kid) 与公有 kid 进行比较。

    1. 下载并存储适用于用户池的对应的公有 JSON Web Key(JWK)。它可作为 JSON Web Key Set (JWKS) 的一部分提供。您可以通过为您的环境构建以下 jwks_uri URL 来找到它:

      https://cognito-idp.<Region>.amazonaws.com/<userPoolId>/.well-known/jwks.json

      有关更多 JWK 和 JWK 集的更多信息,请参阅 JSON Web Key (JWK)

      注意

      Amazon Cognito 可能会轮换用户群体中的签名密钥。最佳做法是使用 kid 作为缓存密钥在应用程序中缓存公有密钥,并定期刷新缓存。将您的应用程序收到的令牌中的 kid 与缓存进行比较。

      如果您收到的令牌的颁发者是正确的,但 kid 不同,则 Amazon Cognito 可能已经轮换了签名密钥。从您的用户群体 jwks_uri 端点刷新缓存。

      这是个 jwks.json 文件示例:

      { "keys": [{ "kid": "1234example=", "alg": "RS256", "kty": "RSA", "e": "AQAB", "n": "1234567890", "use": "sig" }, { "kid": "5678example=", "alg": "RS256", "kty": "RSA", "e": "AQAB", "n": "987654321", "use": "sig" }] }
      密钥 ID(kid

      kid 是一个提示,指示哪个密钥用于保护令牌的 JSON Web 签名(JWS)。

      算法(alg

      alg 标头参数表示用于保护 ID 令牌的加密算法。用户池使用 RS256 加密算法,这是一种采用 SHA-256 的 RSA 签名。有关 RSA 的更多信息,请参阅 RSA 加密

      密钥类型(kty

      kty 参数标识与密钥结合使用的加密算法系列,例如,在本示例中为“RSA”。

      RSA 指数(e

      e 参数包含 RSA 公有密钥的指数值。它表示为采用 Base64urlUInt 编码的值。

      RSA 模数(n

      n 参数包含 RSA 公有密钥的模数值。它表示为采用 Base64urlUInt 编码的值。

      使用(use

      use 参数描述了公有密钥的预期用途。在本示例中,usesig 表示签名。

    2. 搜索与您 JWT 的 kid 相匹配的 kid 的公有 JSON Web 密钥。

  3. 使用 JWT 库将颁发者的签名与令牌中的签名进行比较。发布者签名来自在 jwks.json 中的 kid 公有密钥(RSA 模数 "n"),该公有密钥与令牌 kid 匹配。您可能首先需要将 JWK 转换为 PEM 格式。以下示例采用 JWT 和 JWK 格式,并且使用 Node.js 库 jsonwebtoken 来验证 JWT 签名:

    Node.js
    var jwt = require('jsonwebtoken'); var jwkToPem = require('jwk-to-pem'); var pem = jwkToPem(jwk); jwt.verify(token, pem, { algorithms: ['RS256'] }, function(err, decodedToken) { });

验证声明

验证 JWT 声明
  1. 通过以下方法之一,验证令牌是否未过期。

    1. 对令牌解码并将 exp 声明与当前时间进行比较。

    2. 如果您的访问令牌包含aws.cognito.signin.user.admin索赔,请向类似的 API 发送请求GetUser。如果令牌已过期,您使用访问令牌进行授权的 API 请求会返回错误。

    3. 在针对UserInfo 端点的请求中提供您的访问令牌。如果您的令牌已过期,则请求会返回错误。

  2. ID 令牌中的 aud 声明和访问令牌中的 client_id 声明应与在 Amazon Cognito 用户池中创建的应用程序客户端 ID 匹配。

  3. 发布者 (iss) 声明应与您的用户池匹配。例如,在 us-east-1 区域中创建的用户池将有下列 iss 值:

    https://cognito-idp.us-east-1.amazonaws.com/<userpoolID>.

  4. 检查 token_use 声明。

    • 如果您在 Web API 操作中只接受访问令牌,则其值必须为 access

    • 如果您只使用 ID 令牌,则其值必须为 id

    • 如果您同时使用 ID 令牌和访问令牌,则 token_use 声明必须为 idaccess

您现在可以信任该令牌内的声明。