本文只是对使用aws使用cognito自定义身份验证实践SNS的简单记录,参考文章如上。

  1. 用户在登录页面输入电话号码。
  2. 身份验证挑战定义 Lambda 被执行并确定身份验证流程。
  3. 身份验证质询创建 Lambda 被执行并发出一次性密码(OTP)。
  4. AmazonSNS被调用,SMS 被发送。
  5. 在登录页面输入用户收到的OTP。
  6. 身份验证质询验证 Lambda 被执行以确定输入的 OTP 是否正确
  7. 认证质询定义Lambda被执行,如果判断结果正确,则认证成功并颁发token
  8. 认证成功后,执行认证后Lambda,更新用户属性(验证电话号码)。

    部署资源

    从 AWS Serverless Application Repository 部署 Cognito 用户池和 Lambda 函数。但是这里创建的 Cognito 用户池将不会被使用,稍后会创建,因此您可以在部署后根据需要将其删除。

  9. 访问以下内容并单击 [部署]。
    应用程序搜索 - AWS 无服务器应用程序存储库
    [AWS] 使用 Cognito 自定义身份验证实现 SNS 身份验证 - 图1

  10. 输入发件人邮箱和用户池名称(由于没有使用SES和用户池,可以任意),点击【部署】。
    image.png
  11. 确认从部署历史中显示[创建完成]。
    image.png

创建 Cognito 用户池

由于之前创建的用户池用于电子邮件身份验证,并且在登录选项中指定了电子邮件地址,因此使用为 SMS 身份验证指定的电话号码创建一个新用户池。

  1. 在AWS管理控制台中,转到 Cognito 下的用户池,然后单击创建用户池
    image.png
  2. 按照屏幕上的说明设置每个项目。但是,请务必如下设置以下项目。
    Cognito 用户池登录选项:仅检查电话号码
    image.png 密码策略:至少 8 个字符,取消选中所有密码要求
    image.png 多因素身份验证:无 MFA
    image.png忘记密码
    image.png

注册配置:image.png
image.png
必需属性:电话号码 + 电子邮箱
image.png
配置消息发送
image.png
image.png
身份验证流程:ALLOW_CUSTOM_AUTH
image.png
image.png

  1. 完成设置后,单击[查看和创建]屏幕上的[创建用户池]。
    image.png
  2. 选择创建的用户池,点击【用户池属性】中的【添加 Lambda 触发器】

image.png设置 Lambda 触发器如下。
注册前 Lambda 触发器:PreSignUpVerify
image.png
定义身份验证质询 Lambda 触发器:VerifyAuthChallengeResponseCreate
image.png
创建身份验证质询Lambda 触发器:CreateAuthChallenge
image.png
身份验证质询Lambda 触发器:DefineAuthChallengePost
image.png
身份验证 Lambda 触发器:PostAuthentication
image.png

  1. 从下方检查您的用户池 ID 和用户池客户端 ID。保存这两个以备后用。
    用户池 ID:用户池概览
    image.png用户池客户端 ID:[用户池]-[应用程序集成]-[客户端 ID]
    image.png

修改Lambda函数

创建身份验证(创建身份验证 Lambda)

要授予对SNS的访问权限,请从 [Settings]-[Access Permissions] 添加以下 IAM 策略。允许sns发布
image.png
image.png
与原始代码的主要变化是将发送电子邮件的部分替换为发送 SNS。
image.png

  1. "use strict";
  2. // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. // SPDX-License-Identifier: MIT-0
  4. Object.defineProperty(exports, "__esModule", { value: true });
  5. const crypto_secure_random_digit_1 = require("crypto-secure-random-digit");
  6. const aws_sdk_1 = require("aws-sdk");
  7. const sns = new aws_sdk_1.SNS();
  8. exports.handler = async (event) => {
  9. let secretLoginCode;
  10. if (!event.request.session || !event.request.session.length) {
  11. // This is a new auth session
  12. // Generate a new secret login code and mail it to the user
  13. console.log(event.request.session);
  14. secretLoginCode = crypto_secure_random_digit_1.randomDigits(6).join('');
  15. await sendSMSviaSNS(event.request.userAttributes.phone_number, secretLoginCode);
  16. }
  17. else {
  18. // There's an existing session. Don't generate new digits but
  19. // re-use the code from the current session. This allows the user to
  20. // make a mistake when keying in the code and to then retry, rather
  21. // then needing to e-mail the user an all new code again.
  22. console.log(event.request.session);
  23. const previousChallenge = event.request.session.slice(-1)[0];
  24. secretLoginCode = previousChallenge.challengeMetadata.match(/CODE-(\d*)/)[1];
  25. }
  26. // This is sent back to the client app
  27. event.response.publicChallengeParameters = { phone: event.request.userAttributes.phone_number };
  28. // Add the secret login code to the private challenge parameters
  29. // so it can be verified by the "Verify Auth Challenge Response" trigger
  30. event.response.privateChallengeParameters = { secretLoginCode };
  31. // Add the secret login code to the session so it is available
  32. // in a next invocation of the "Create Auth Challenge" trigger
  33. event.response.challengeMetadata = `CODE-${secretLoginCode}`;
  34. return event;
  35. };
  36. async function sendSMSviaSNS(phoneNumber, secretLoginCode) {
  37. const params = { "Message": "Your secret code: " + secretLoginCode, "PhoneNumber": phoneNumber };
  38. await sns.publish(params).promise();
  39. }

身份验证后Lambda

post-authentication.js,原代码更新了邮箱地址的属性,但是这次我们用的是电话号码,所以我们改成更新电话号码。

  1. "use strict";
  2. // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. // SPDX-License-Identifier: MIT-0
  4. Object.defineProperty(exports, "__esModule", { value: true });
  5. const aws_sdk_1 = require("aws-sdk");
  6. const cup = new aws_sdk_1.CognitoIdentityServiceProvider();
  7. exports.handler = async (event) => {
  8. if (event.request.userAttributes.phone_number_verified !== 'true') {
  9. const params = {
  10. UserPoolId: event.userPoolId,
  11. UserAttributes: [{
  12. Name: 'phone_number_verified',
  13. Value: 'true',
  14. }],
  15. Username: event.userName,
  16. };
  17. await cup.adminUpdateUserAttributes(params).promise();
  18. }
  19. return event;
  20. };