自定义身份验证质询 Lambda 触发器 - Amazon Cognito
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

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

自定义身份验证质询 Lambda 触发器

在为 Amazon Cognito 用户池构建身份验证流程时,您可能会发现需要在内置流程的基础上对身份验证模型进行扩展。自定义质询触发器的一个常见使用场景是在用户名、密码和多重身份验证(MFA)之外实施额外的安全检查。自定义质询是您可以使用 Lambda 支持的编程语言生成的任何问题和回答。例如,在允许用户进行身份验证之前,您可能希望要求用户先破解验证码或回答安全问题。另一个潜在的需求是与专门的身份验证因素或设备集成。或者,您可能已经开发了使用硬件安全密钥或生物识别设备对用户进行身份验证的软件。自定义质询的身份验证成功的定义是,您的 Lambda 函数接受为正确的答案:例如,固定字符串或来自外部 API 的满意响应。

您可以使用自定义质询开始身份验证并完全控制身份验证过程,也可以在应用程序收到自定义质询之前执行用户名和密码身份验证。

自定义身份验证质询 Lambda 触发器:

定义

启动质询序列。确定您是要启动新的质询、将身份验证标记为已完成,还是要停止身份验证尝试。

创建

向您的应用程序发出用户必须回答的问题。此函数可能会呈现安全问题或指向验证码的链接,您的应用程序应将其显示给用户。

验证

知道预期答案并将其与您的应用程序在质询响应中提供的答案进行比较。该函数可能会调用您的验证码服务的 API 来检索用户尝试的解决方案的预期结果。

这三个 Lambda 函数链接在一起,呈现出一种完全由您控制且由您自己设计的身份验证机制。由于自定义身份验证需要在您的客户端和 Lambda 函数中使用应用程序逻辑,因此您无法在托管登录中处理自定义身份验证。此身份验证系统需要开发人员付出额外的努力。您的应用程序必须使用用户池 API 执行身份验证流程,并使用自定义的登录界面来处理由此产生的挑战,该界面将问题呈现为自定义身份验证质询的中心。

质询 Lambda 触发器

有关实施自定义身份验证的更多信息,请参阅自定义身份验证流程和质询

API 操作之间的身份验证InitiateAuthAdminInitiateAuth、和RespondToAuthChallengeAdminRespondToAuthChallenge。在此流程中,用户通过回答连续的质询进行身份验证,直到身份验证失败或用户获得令牌。质询回应可能是一个新的挑战。在这种情况下,您的应用程序会根据需要多次响应新的质询。当定义身份验证质询函数分析到目前为止的结果时,确定所有质询都已回答并返回 IssueTokens 时,身份验证就会成功。

自定义质询流程中的 SRP 身份验证

您可以让 Amazon Cognito 在发出自定义质询之前验证用户密码。当您在自定义质询流程中执行 SRP 身份验证时,请求频率限额身份验证类别中关联的任何 Lambda 触发器都将运行。过程概述如下:

  1. 您的应用程序使用 AuthParameters 映射来调用 InitiateAuthAdminInitiateAuth,以此来启动登录。参数必须包括 CHALLENGE_NAME: SRP_A, 以及 SRP_AUSERNAME 的值。

  2. Amazon Cognito 使用包含 challengeName: SRP_AchallengeResult: true 的初始会话,调用您定义的身份验证质询 Lambda 触发器。

  3. 在收到这些输入后,您的 Lambda 函数发出 challengeName: PASSWORD_VERIFIERissueTokens: falsefailAuthentication: false 响应。

  4. 如果密码验证成功,Amazon Cognito 会使用包含 challengeName: PASSWORD_VERIFIERchallengeResult: true 的新会话再次调用您的 Lambda 函数。

  5. 为了启动您的自定义质询,Lambda 函数发出 challengeName: CUSTOM_CHALLENGEissueTokens: falsefailAuthentication: false 响应。如果您不想启动包含密码验证的自定义身份验证流程,可以使用 AuthParameters 映射(包括 CHALLENGE_NAME: CUSTOM_CHALLENGE)启动登录。

  6. 质询循环将一直重复到所有质询得到应答。

以下在使用 SRP 流进行自定义身份验证之前的起始 InitiateAuth 请求的示例。

{ "AuthFlow": "CUSTOM_AUTH", "ClientId": "1example23456789", "AuthParameters": { "CHALLENGE_NAME": "SRP_A", "USERNAME": "testuser", "SRP_A": "[SRP_A]", "SECRET_HASH": "[secret hash]" } }

在自定义身份验证 SRP 流程中重置密码

当用户处于FORCE_CHANGE_PASSWORD状态时,您的自定义身份验证流程必须集成密码更改步骤,同时保持身份验证质询的完整性。Amazon Cognito 会在挑战期间调用你的定义身份验证挑战 Lambda 触发器。NEW_PASSWORD_REQUIRED在这种情况下,使用自定义质询流程和 SRP 身份验证登录的用户如果处于密码重置状态,则可以设置新密码。

当用户处于RESET_REQUIREDFORCE_CHANGE_PASSWORD状态时,他们必须使用来回应NEW_PASSWORD_REQUIRED挑战NEW_PASSWORD。在使用 SRP 的自定义身份验证中,Amazon Cognito 会在用户完成 SRP 挑战后返回NEW_PASSWORD_REQUIRED一个质询。PASSWORD_VERIFIER您的 define auth 质询触发器会收到session数组中的两个质询结果,并且可以在用户成功更改密码后继续执行其他自定义质询。

您的定义身份验证挑战 Lambda 触发器必须通过 SRP 身份验证、密码重置和随后的自定义质询来管理质询序列。触发器在session参数中接收一系列已完成的挑战,包括两者PASSWORD_VERIFIER兼而有NEW_PASSWORD_REQUIRED之。有关实现示例,请参阅定义身份验证质询示例

身份验证流程步骤

对于需要在自定义质询之前验证密码的用户,该过程遵循以下步骤:

  1. 您的应用程序使用 AuthParameters 映射来调用 InitiateAuthAdminInitiateAuth,以此来启动登录。参数必须包括CHALLENGE_NAME: SRP_A、以及SRP_A和的值USERNAME

  2. Amazon Cognito 使用包含 challengeName: SRP_AchallengeResult: true 的初始会话,调用您定义的身份验证质询 Lambda 触发器。

  3. 在收到这些输入后,您的 Lambda 函数发出 challengeName: PASSWORD_VERIFIERissueTokens: falsefailAuthentication: false 响应。

  4. 如果密码验证成功,则会发生以下两种情况之一:

    对于处于正常状态的用户:

    Amazon Cognito 使用包含和的新会话再次调用你的 Lambda 函数。challengeName: PASSWORD_VERIFIER challengeResult: true

    为了启动您的自定义质询,Lambda 函数发出 challengeName: CUSTOM_CHALLENGEissueTokens: falsefailAuthentication: false 响应。

    对于处于RESET_REQUIREDFORCE_CHANGE_PASSWORD状态的用户:

    Amazon Cognito 使用包含和的会话调用你的 Lambda 函数。challengeName: PASSWORD_VERIFIER challengeResult: true

    您的 Lambda 函数应该使用 challengeName: NEW_PASSWORD_REQUIREDissueTokens: falsefailAuthentication: false 作出响应。

    成功更改密码后,Amazon Cognito 将使用包含和结果的会话调用您的 Lambda 函数。PASSWORD_VERIFIER NEW_PASSWORD_REQUIRED

    为了启动您的自定义质询,Lambda 函数发出 challengeName: CUSTOM_CHALLENGEissueTokens: falsefailAuthentication: false 响应。

  5. 质询循环将一直重复到所有质询得到应答。

如果您不想启动包含密码验证的自定义身份验证流程,可以使用 AuthParameters 映射(包括 CHALLENGE_NAME: CUSTOM_CHALLENGE)启动登录。

会话管理

身份验证流程通过一系列会话 IDs 和质询结果保持会话的连续性。每个质询响应都会生成一个新的会话 ID,以防止会话重用错误,这对于多因素身份验证流程尤其重要。

质询结果按时间顺序存储在您的 Lambda 触发器接收的会话数组中。对于处于FORCE_CHANGE_PASSWORD状态的用户,会话数组包含:

  1. session[0]-最初的SRP_A挑战

  2. session[1]-PASSWORD_VERIFIER 结果

  3. session[2]-NEW_PASSWORD_REQUIRED 结果

  4. 后续元素-其他自定义挑战的结果

身份验证流程示例

以下示例演示了一个完整的自定义身份验证流程,该用户必须同时完成密码更改和自定义 CAPTCHA 质询。FORCE_CHANGE_PASSWORD

  1. InitiateAuth request

    { "AuthFlow": "CUSTOM_AUTH", "ClientId": "1example23456789", "AuthParameters": { "CHALLENGE_NAME": "SRP_A", "USERNAME": "testuser", "SRP_A": "[SRP_A]" } }
  2. InitiateAuth 响应

    { "ChallengeName": "PASSWORD_VERIFIER", "ChallengeParameters": { "USER_ID_FOR_SRP": "testuser" }, "Session": "[session_id_1]" }
  3. RespondToAuthChallenge 请求用 PASSWORD_VERIFIER

    { "ChallengeName": "PASSWORD_VERIFIER", "ClientId": "1example23456789", "ChallengeResponses": { "PASSWORD_CLAIM_SIGNATURE": "[claim_signature]", "PASSWORD_CLAIM_SECRET_BLOCK": "[secret_block]", "TIMESTAMP": "[timestamp]", "USERNAME": "testuser" }, "Session": "[session_id_1]" }
  4. RespondToAuthChallenge 用NEW_PASSWORD_REQUIRED挑战回应

    { "ChallengeName": "NEW_PASSWORD_REQUIRED", "ChallengeParameters": {}, "Session": "[session_id_2]" }
  5. RespondToAuthChallenge 请求用 NEW_PASSWORD_REQUIRED

    { "ChallengeName": "NEW_PASSWORD_REQUIRED", "ClientId": "1example23456789", "ChallengeResponses": { "NEW_PASSWORD": "[password]", "USERNAME": "testuser" }, "Session": "[session_id_2]" }
  6. RespondToAuthChallenge 使用 CAPTCHA 自定义挑战进行回应

    { "ChallengeName": "CUSTOM_CHALLENGE", "ChallengeParameters": { "captchaUrl": "url/123.jpg" }, "Session": "[session_id_3]" }
  7. RespondToAuthChallenge 请求并附上 CAPTCHA 自定义挑战的答案

    { "ChallengeName": "CUSTOM_CHALLENGE", "ClientId": "1example23456789", "ChallengeResponses": { "ANSWER": "123", "USERNAME": "testuser" }, "Session": "[session_id_3]" }

6。最终成功响应

{ "AuthenticationResult": { "AccessToken": "eyJra456defEXAMPLE", "ExpiresIn": 3600, "IdToken": "eyJra789ghiEXAMPLE", "RefreshToken": "eyJjd123abcEXAMPLE", "TokenType": "Bearer" }, "ChallengeParameters": {} }