iOS应用基于AWS User Pool实现仅手机号登录:已确认用户OTP发送方法
嘿,刚好做过类似的AWS Cognito登录流程,给你详细说下怎么给已确认状态的用户发送登录用的OTP,分两种实用方案,你可以根据自己的场景选择:
方案1:自定义认证流程(推荐纯OTP登录场景)
这是最灵活的方式,适合完全基于手机号+OTP的无密码登录,核心是借助Cognito的自定义认证触发器和API完成流程:
步骤拆解
- 配置Cognito User Pool触发器
- 进入你的User Pool控制台,找到「触发器」选项卡,设置「自定义认证(Custom Auth)」对应的Lambda函数,这个函数负责生成OTP、发送短信以及验证OTP。
- 前端发起登录请求
调用InitiateAuthAPI,告诉Cognito要启动自定义认证流程:import { CognitoIdentityProviderClient, InitiateAuthCommand } from "@aws-sdk/client-cognito-identity-provider"; const client = new CognitoIdentityProviderClient({ region: "你的AWS区域" }); const initiateAuthParams = { AuthFlow: "CUSTOM_AUTH", ClientId: "你的App Client ID", AuthParameters: { USERNAME: "用户输入的手机号" // 假设你的用户名是手机号 } }; const command = new InitiateAuthCommand(initiateAuthParams); const response = await client.send(command); // 此时会收到 ChallengeName: "CUSTOM_CHALLENGE" 和 Session 会话值 - Lambda生成并发送OTP
自定义认证Lambda会被触发,生成随机OTP并通过短信发送给用户,同时临时存储OTP用于后续验证:const AWS = require('aws-sdk'); const sns = new AWS.SNS({ region: '你的AWS区域' }); const crypto = require('crypto'); exports.handler = async (event) => { if (event.request.challengeName === 'CUSTOM_CHALLENGE') { // 第一次触发:生成并发送OTP if (!event.request.session || event.request.session.length === 0) { const otp = crypto.randomInt(100000, 999999).toString(); // 把OTP存到Cognito的私有挑战参数中,后续验证用 event.response.privateChallengeParameters = { otp }; // 用SNS发送验证码短信 await sns.publish({ Message: `你的登录验证码是:${otp}(5分钟内有效)`, PhoneNumber: event.userName // 用户名即手机号 }).promise(); event.response.challengeMetadata = 'CUSTOM_OTP_CHALLENGE'; } else { // 第二次触发:验证用户提交的OTP const expectedOtp = event.request.privateChallengeParameters.otp; const submittedOtp = event.request.challengeAnswer; if (submittedOtp === expectedOtp) { event.response.issueTokens = true; // 验证通过,颁发令牌 event.response.failAuthentication = false; } else { event.response.issueTokens = false; event.response.failAuthentication = true; } } } return event; }; - 前端提交OTP完成登录
用户收到验证码后,调用RespondToAuthChallengeAPI提交OTP,完成认证:import { RespondToAuthChallengeCommand } from "@aws-sdk/client-cognito-identity-provider"; const respondParams = { ChallengeName: "CUSTOM_CHALLENGE", ClientId: "你的App Client ID", Session: response.Session, // 上一步InitiateAuth返回的会话值 ChallengeResponses: { USERNAME: "用户输入的手机号", ANSWER: "用户输入的6位OTP" } }; const respondCommand = new RespondToAuthChallengeCommand(respondParams); const authResult = await client.send(respondCommand); // authResult中包含IdToken、AccessToken、RefreshToken,完成登录
方案2:借助SMS MFA(适合已有密码+二次验证场景)
如果你的用户池已经启用了SMS多因素认证,且用户已绑定手机号作为MFA方式,可以用这个流程:
- 前端调用
InitiateAuth(AuthFlow设为USER_PASSWORD_AUTH或USER_SRP_AUTH),传入用户名和密码; - Cognito会触发MFA挑战,自动发送OTP到用户手机号;
- 用户输入OTP后,调用
RespondToAuthChallenge完成登录。
不过这个方案需要用户设置密码,如果你是纯无密码的OTP登录,方案1更适配你的需求。
关键注意事项
- 确保你的App Client已启用对应的认证流程(比如「自定义认证」),在App Client的「认证流程」选项中勾选对应选项;
- 发送短信的Lambda需要配置SNS的
Publish权限; - OTP建议设置过期时间(比如5分钟),避免重复使用,你可以在Lambda中加入时间戳逻辑来校验。
内容的提问来源于stack exchange,提问作者user3202457
相关产品推荐
相关产品推荐

