向 Amazon Cognito 发送自定义属性并将其注入令牌中 - AWS Prescriptive Guidance

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

向 Amazon Cognito 发送自定义属性并将其注入令牌中

Amazon Web Services 的卡洛斯·亚历山德罗·里贝罗和毛里西奥·门多萨

摘要

向 Amazon Cognito 身份验证过程发送自定义属性可以为应用程序提供更多背景信息,实现更精细的访问控制,并更轻松地管理用户资料和身份验证要求。这些功能在各种应用程序和场景中都很有用,它们可以帮助您提高应用程序的整体安全性和功能。

此模式显示当应用程序需要为访问令牌或身份 (ID) 令牌提供其他上下文时,如何向 Amazon Cognito 身份验证过程发送自定义属性。您可以使用 Node.js 作为后端应用程序。该应用程序对 Amazon Cognito 用户池中的用户进行身份验证,并传递生成令牌所需的自定义属性。您可以使用 Amazon Cognito 的AWS Lambda 触发器自定义您的身份验证流程,而无需进行大量的代码自定义或花费大量精力。

重要

不建议将此模式中的代码和示例用于生产工作负载,因为它们仅用于演示目的。对于生产工作负载,需要在客户端进行其他配置。使用此模式仅供飞行员参考,或仅供参 proof-of-concept考。

先决条件和限制

先决条件

限制

  • 此模式不适用于通过客户端凭证身份验证流程进行应用程序集成。

  • 令牌生成前触发器只能添加或更改访问令牌和身份令牌的某些属性。有关更多信息,请参阅 Amazon Cognito 文档中的代币生成前 Lambda 触发器

架构

目标架构

下图显示了此模式的目标架构。它还展示了 Node.js 应用程序如何使用后端来更新数据库。但是,后端数据库更新不在此模式的范围之内。

一个向 Amazon Cognito 用户池颁发带有自定义属性的访问令牌的 Node.js 应用程序。

图表显示了以下工作流:

  1. Node.js 应用程序向 Amazon Cognito 用户池发布带有自定义属性的访问令牌。

  2. Amazon Cognito 用户池启动令牌生成前 Lambda 函数,该函数可自定义访问令牌和 ID 令牌。

  3. Node.js 应用程序通过 Amazon API Gateway 进行 API 调用。

注意

例如,此架构中显示的其他架构组件仅供参考,超出了此模式的范围。

自动化和扩缩

您可以使用AWS CloudFormation、、HashiCorp Terraform 或任何支持的基础设施即代码 (IaC) 工具,自动配置 Amazon Cognito 用户池、 AWS Lambda 函数、数据库实例和其他资源。AWS Cloud Development Kit (AWS CDK)如果您想扩展部署,请使用持续集成和持续交付 (CI/CD) 管道,这有助于防止与手动部署相关的错误。

工具

AWS 服务

  • Amazon API Gateway 可帮助您创建、发布、维护、监控和保护任何规模的 RES WebSocket APIs T、HTTP。

  • Amazon Cognito 为您的 Web 和移动应用程序提供身份验证、授权和用户管理。

  • Amazon Elastic Container Service (Amazon ECS)是一项快速且可扩展的容器管理服务,可帮助运行、停止和管理集群上的容器。

  • AWS Lambda 是一项计算服务,可帮助您运行代码,无需预置或管理服务器。它仅在需要时运行您的代码,并且能自动扩缩,因此您只需为使用的计算时间付费。

  • 适用于 JavaScript 的 AWS SDK为提供了 JavaScript API AWS 服务。您可以使用它为 Node.js 或浏览器构建库或应用程序。

其他工具

  • Node.js 是一个事件驱动的 JavaScript 运行时环境,专为构建可扩展的网络应用程序而设计。

  • npm 是在 Node.js 环境中运行的软件注册表,用于共享或借用软件包以及管理私有软件包的部署。

最佳实践

我们建议您实施以下最佳实践:

  • 机密和敏感数据-请勿在应用程序中存储机密或敏感数据。使用应用程序可以从中提取数据的外部系统,例如AWS AppConfigAWS Secrets Manager、或 P AWS Systems Manager arameter Store

  • 标准化部署-使用 CI/CD 管道部署应用程序。您可以使用AWS CodeBuild和之类的服务AWS CodePipeline

  • 令牌到期-为访问令牌设置一个较短的到期日期。

  • 使用安全连接-客户端应用程序和后端之间的所有通信都应使用 SSL/TLS 进行加密。使用 AWS Certificate Manager (ACM) 生成和管理 SSL/TLS 证书,并使用 Amazon CloudFrontElastic Load Balancing 来处理 SSL/TLS 终止问题。

  • 验证用户输入-确保所有用户输入都经过验证,以防止注入攻击和其他安全漏洞。使用输入验证库和服务(例如 Amazon API Gateway)AWS WAF,并防范常见的攻击媒介。

  • 使用 IAM 角色-使用 AWS Identity and Access Management (IAM) 角色控制对 AWS 资源的访问权限,并确保只有经过授权的用户才能访问资源。遵循最低权限原则,并确保每个用户仅拥有履行其角色所需的权限。

  • 使用密码策略-配置符合您的安全要求的密码策略,例如最小长度、复杂性和到期时间。使用 Secrets Manag AWS Systems Manager er 或 Parameter Store 来安全地存储和管理密码。

  • 启用多因素身份验证 (MFA)-为所有用户启用 MFA,以提供额外的安全层并降低未经授权访问的风险。使用AWS IAM Identity Center或 Amazon Cognito 启用 MFA 和其他身份验证方法。

  • 安全存储敏感信息-使用 AWS Key Management Service (AWS KMS) 或其他加密服务安全地存储敏感信息,例如密码和访问令牌。

  • 使用强身份验证方法-要提高身份验证过程的安全性,请使用强身份验证方法,例如生物识别身份验证或多因素身份验证。

  • 监控可疑活动-使用AWS CloudTrail和其他监控工具来监控可疑活动和潜在的安全威胁。为异常活动设置自动警报,并使用 Amazon GuardDutyAWS Security Hub来检测潜在威胁。

  • 定期审查和更新安全政策 — 定期审查和更新您的安全策略和程序,以确保它们符合您不断变化的安全要求和最佳实践。 AWS Config 用于跟踪和审核安全策略和程序的更改。

  • 自动注册 — 请勿启用自动注册 Amazon Cognito 用户池。有关更多信息,请参阅使用 Amazon Cognito 用户池降低用户注册欺诈和短信激增的风险AWS (博客文章)。

有关其他最佳实践,请参阅 Amazon Cognito 文档中的 Amazon Cognito 用户池安全最佳实践

操作说明

Task描述所需技能

创建用户池。

  1. 在 CLI 终端中,输入以下命令以创建 Amazon Cognito 用户池:

    aws cognito-idp create-user-pool \ --pool-name <MyUserPool>
  2. 输入以下命令来创建客户端 ID 和密钥,以便与 SDK 一起使用 JavaScript:

    aws cognito-idp create-user-pool-client \ --user-pool-id <UserPoolID> \ --client-name <MyNewClient> \ --no-generate-secret \ --explicit-auth-flows "USER_PASSWORD_AUTH" "ADMIN_NO_SRP_AUTH"

有关如何在中设置用户池的更多信息和说明 AWS Management Console,请参阅用户池入门和向用户池添加更多功能和安全选项

提示

要降低成本,请使用基本计划或精简版计划来测试此模式。有关更多信息,请参阅 Amazon Cognito 定价

AWS 应用程序开发人员 DevOps

向用户池中添加用户。

输入以下命令在 Amazon Cognito 用户池中创建一个用户:

aws cognito-idp sign-up \ --client-id <ClientID> \ --username <jane@example.com> \ --password <PASSWORD> \ --user-attributes Name="email",Value="<jane@example.com>" Name="name",Value="<Jane>"
AWS 应用程序开发人员 DevOps

将应用程序客户端添加到用户池中。

  1. 导航到 Amazon Cognito 控制台

  2. 选择用户池

  3. 选择您之前创建的用户池。

  4. 在 “定义您的应用程序” 下,选择最适合您要为其创建身份验证和授权服务的应用程序场景的应用程序类型

  5. 命名您的应用程序中,输入描述性名称或继续使用默认名称。

  6. 在 “添加返回 URL” 下,输入用户完成身份验证后的应用程序重定向路径。

  7. 选择 “创建您的应用程序”。您可以在创建应用程序客户端后设置高级选项。

AWS 系统管理员、AWS 管理员、AWS DevOps、应用程序开发者

为代币前生成创建一个 Lambda 触发器。

  1. 打开 Lamba 控制台的 Functions page(函数页面)。

  2. 选择 Create function(创建函数)。

  3. 选择从头开始编写

  4. 基本信息窗格中,在函数名称中输入myPreTokenGenerationLambdaFunction

  5. 对于 Runtime,选择 Node.js 22

  6. 架构设置为 x86_64

  7. 选择创建函数

  8. 在 “代码” 选项卡上的 “代码源” 下,输入此模式的 “其他资源” 部分中的示例 Lambda 函数。此 Lambda 函数将自定义属性注入到 ID 令牌和访问令牌中。

AWS DevOps,应用程序开发者

自定义用户池工作流程。

  1. 导航到 Amazon Cognito 控制台

  2. 选择用户池

  3. 选择您之前创建的用户池。

  4. 在左侧导航窗格的 “身份验证” 下,选择 “扩展”。

  5. 选择添加 Lambda 触发器。

  6. 添加或编辑令牌生成前触发器

  7. 对于 “触发器类型”,选择 “身份验证”。

  8. 在 “身份验证” 下,选择令牌生成前触发器

  9. 对于分配 Lambda 函数,请选择。myPreTokenGenerationLambdaFunction

  10. 选择添加 Lambda 触发器。

  11. 选择触发事件版本的基本功能+用户身份的访问令牌自定义或基本功能+用户和计算机身份的访问令牌自定义。此设置会更新 Amazon Cognito 发送给您的函数的请求参数,使该函数包含用于自定义访问令牌的字段。

有关更多信息,请参阅 Amazon Cognito 文档中的使用 Lambda 触发器自定义用户池工作流程

AWS DevOps,应用程序开发者
Task描述所需技能

创建 Node.js 应用程序。

  1. 在终端中,输入以下命令:

    mkdir my-app cd my-app npm init -y npm install --save-dev typescript npm i --save-dev @types/node npm i amazon-cognito-identity-js npx tsc --init mkdir src touch src/index.ts
  2. 修改package.json文件以包含编 TypeScript 译脚本:

    "scripts": { "start": "node src/index.js", "build": "tsc" },
应用程序开发人员

实现身份验证逻辑。

  1. 打开 index.ts文件。

  2. 粘贴此模式的 “其他资源” 部分中提供的样本 Typescript。

  3. 保存并关闭 index.ts文件。

注意

您可以根据自己的用例创建自己的 TypeScript 文件或修改所提供的示例。

应用程序开发人员

配置环境变量和配置文件。

在终端中,输入以下命令来创建环境变量:

export USERNAME="<COGNITO_USER_NAME>" export PASSWORD="<COGNITO_USER_PASSWORD>" export USER_POOL_ID="<COGNITO_USER_ID>" export CLIENT_ID="<COGNITO_CLIENT_ID>"
重要

请勿对机密进行硬编码或泄露您的凭据。

应用程序开发人员

运行应用程序。

输入以下命令以运行应用程序并确认其运行正常:

npm run build npm start
应用程序开发人员

确认自定义属性已注入令牌。

使用 IDE 的调试功能查看访问权限和 ID 令牌。确认已添加自定义属性。有关示例代币,请参阅此模式的 “其他信息” 部分。

应用程序开发人员

故障排除

事务解决方案

尝试对用户进行身份验证时客户端 ID 无效

当您将客户端 ID 与生成的客户端密钥一起使用时,通常会发生此错误。您必须创建一个不附带密钥的客户端 ID。有关更多信息,请参阅应用程序客户端的应用程序特定设置

相关资源

其他信息

示例 TypeScript 文件

以下代码示例是一个通过使用 AWS 软件开发工具包向 Amazon Cognito 发送自定义属性来调用身份验证过程的 TypeScript 文件:

import * as AmazonCognitoIdentity from "amazon-cognito-identity-js"; const userPoolId: string = process.env.USER_POOL_ID ?? ''; const clientId: string = process.env.CLIENT_ID ?? ''; const poolData = { UserPoolId: userPoolId, ClientId: clientId }; const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); export const loginWithCognitoSDK = function (userName: string, password: string) { const authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({ Username: userName, Password: password, ClientMetadata: { customGroup: "MyCustomGroup", customApplicationData: "Custom data from a custom application" } }); const userData = { Username: userName, Pool: userPool }; const cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData); // Authenticate the user using the authenticationDetails object cognitoUser.authenticateUser(authenticationDetails, { onSuccess: function (result: any) {}, onFailure: function (err: any) {}, }); } loginWithCognitoSDK(process.env.USERNAME ?? '', process.env.PASSWORD ?? '');

该示例使用的 SDK 中的AuthenticationDetails模型 JavaScript 来提供用户名、密码和ClientMetadada。在 Amazon Cognito 中进行身份验证后,可以从访问令牌和 ID 令牌中检索客户端元数据。

示例 Lambda 函数

以下代码示例是一个 Lambda 函数,该函数链接到 Amazon Cognito 中的生成前代币。它可以帮助您自定义 Amazon Cognito 使用的访问令牌和 ID 令牌。代币通过您的架构之间的集成传递。此示例包括名为的自定义声明属customApplicationData性和名为:的自定义群组名称MyCustomGroup

export const handler = async(event, context, callback) => { event.response = { claimsOverrideDetails: { claimsToAddOrOverride: { customApplicationData: event.request.clientMetadata.customApplicationData }, groupOverrideDetails: { groupsToOverride: [event.request.clientMetadata.customGroup] } } }; callback(null, event); };

访问令牌示例

您可以解码访问令牌以可视化已添加的自定义属性。以下是访问令牌示例:

{ "sub": "6daf331f-4451-48b4-abde-774579299204", "cognito:groups": [ "MyCustomGroup" ], "iss": "https://cognito-idp.<REGION>.amazonaws.com/<USERPOOL_ID>", "client_id": "<YOUR_CLIENT_ID>", "origin_jti": "acff7e91-09f9-4fde-8eec-38b0f8c47cdc", "event_id": "c5113a9c-1f01-435b-9b73-a5cd3e88514e", "token_use": "access", "scope": "aws.cognito.signin.user.admin", "auth_time": 1677979246, "exp": 1677982846, "iat": 1677979246, "jti": "5c9c2708-a871-4428-bd9b-18ad261bea90", "username": "<USER_NAME>" }

ID 令牌示例

您可以解码访问令牌以可视化已添加的自定义属性。以下是访问令牌示例:

{ "sub": "6daf331f-4451-48b4-abde-774579299204", "cognito:groups": [ "MyCustomGroup" ], "iss": "https://cognito-idp.<REGION>.amazonaws.com/<USERPOOL_ID>", "cognito:username": "<USER_NAME>", "origin_jti": "acff7e91-09f9-4fde-8eec-38b0f8c47cdc", "customApplicationData": "Custom data from a custom application", "aud": "<YOUR_CLIENT_ID>", "event_id": "c5113a9c-1f01-435b-9b73-a5cd3e88514e", "token_use": "id", "auth_time": 1677979246, "exp": 1677982846, "iat": 1677979246, "jti": "f7ca006b-f25b-44d2-a7a4-6e6423f4201f", "email": "<USER_EMAIL>" }