本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
向 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 应用程序如何使用后端来更新数据库。但是,后端数据库更新不在此模式的范围之内。

图表显示了以下工作流:
Node.js 应用程序向 Amazon Cognito 用户池发布带有自定义属性的访问令牌。
Amazon Cognito 用户池启动令牌生成前 Lambda 函数,该函数可自定义访问令牌和 ID 令牌。
Node.js 应用程序通过 Amazon API Gateway 进行 API 调用。
注意
例如,此架构中显示的其他架构组件仅供参考,超出了此模式的范围。
自动化和扩缩
您可以使用AWS CloudFormation、、HashiCorp Terraform
工具
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 或浏览器构建库或应用程序。
其他工具
最佳实践
我们建议您实施以下最佳实践:
机密和敏感数据-请勿在应用程序中存储机密或敏感数据。使用应用程序可以从中提取数据的外部系统,例如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 CloudFront 或 Elastic 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 GuardDuty 或AWS Security Hub来检测潜在威胁。
定期审查和更新安全政策 — 定期审查和更新您的安全策略和程序,以确保它们符合您不断变化的安全要求和最佳实践。 AWS Config 用于跟踪和审核安全策略和程序的更改。
自动注册 — 请勿启用自动注册 Amazon Cognito 用户池。有关更多信息,请参阅使用 Amazon Cognito 用户池降低用户注册欺诈和短信激增的风险
AWS (博客文章)。
有关其他最佳实践,请参阅 Amazon Cognito 文档中的 Amazon Cognito 用户池安全最佳实践。
操作说明
Task | 描述 | 所需技能 |
---|---|---|
创建用户池。 |
有关如何在中设置用户池的更多信息和说明 AWS Management Console,请参阅用户池入门和向用户池添加更多功能和安全选项。 提示要降低成本,请使用基本计划或精简版计划来测试此模式。有关更多信息,请参阅 Amazon Cognito 定价 | AWS 应用程序开发人员 DevOps |
向用户池中添加用户。 | 输入以下命令在 Amazon Cognito 用户池中创建一个用户:
| AWS 应用程序开发人员 DevOps |
将应用程序客户端添加到用户池中。 |
| AWS 系统管理员、AWS 管理员、AWS DevOps、应用程序开发者 |
为代币前生成创建一个 Lambda 触发器。 |
| AWS DevOps,应用程序开发者 |
自定义用户池工作流程。 |
有关更多信息,请参阅 Amazon Cognito 文档中的使用 Lambda 触发器自定义用户池工作流程。 | AWS DevOps,应用程序开发者 |
Task | 描述 | 所需技能 |
---|---|---|
创建 Node.js 应用程序。 |
| 应用程序开发人员 |
实现身份验证逻辑。 |
注意您可以根据自己的用例创建自己的 TypeScript 文件或修改所提供的示例。 | 应用程序开发人员 |
配置环境变量和配置文件。 | 在终端中,输入以下命令来创建环境变量:
重要请勿对机密进行硬编码或泄露您的凭据。 | 应用程序开发人员 |
运行应用程序。 | 输入以下命令以运行应用程序并确认其运行正常:
| 应用程序开发人员 |
确认自定义属性已注入令牌。 | 使用 IDE 的调试功能查看访问权限和 ID 令牌。确认已添加自定义属性。有关示例代币,请参阅此模式的 “其他信息” 部分。 | 应用程序开发人员 |
故障排除
事务 | 解决方案 |
---|---|
尝试对用户进行身份验证时客户端 ID 无效 | 当您将客户端 ID 与生成的客户端密钥一起使用时,通常会发生此错误。您必须创建一个不附带密钥的客户端 ID。有关更多信息,请参阅应用程序客户端的应用程序特定设置。 |
相关资源
使用 Lambda 触发器自定义用户池工作流程(亚马逊 Cognito 文档)
代币生成前 Lambda 触发器(亚马逊 Cog nito 文档)
CognitoIdentityProviderClient(适用于 JavaScript 的 AWS SDK 文档)
cognito-idp(文档)
AWS CLI
其他信息
示例 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>" }