如何用Node.js AWS SDK验证Cognito登录时的SMS_MFA验证码?
解决AWS Cognito SMS_MFA挑战验证的"Invalid session for the user"错误
你的问题出在错误使用了verifySoftwareToken方法——这个API是用来注册软件令牌(如TOTP)的,并非用于响应SMS_MFA登录挑战。处理SMS验证码验证的正确方法是调用respondToAuthChallenge接口。
正确的verifyMFACode实现
async verifyMFACode(payload, cb) { try { const params = { ClientId: this.clientId, // 必须和登录时用的ClientId一致 ChallengeName: "SMS_MFA", Session: payload.Session, // 前端传来的会话值 AuthParameters: { USERNAME: payload.username, // 可从第一次返回的ChallengeParameters.USER_ID_FOR_SRP获取,由前端传入 SMS_MFA_CODE: payload.userCode // 用户输入的6位SMS验证码 } }; this.cognitoIdentity.respondToAuthChallenge(params, (err, data) => { if (err) { console.log("verifyMFACode error:", err); cb(err); } else { // 验证成功后,会返回AccessToken、RefreshToken、IdToken等令牌 cb(null, data); } }); } catch (err) { console.log("verifyMFACode exception:", err); cb(err); } }
关键说明
- 参数要求:
ClientId必须与登录时使用的客户端ID一致,否则会直接导致会话无效。AuthParameters必须包含两个字段:USERNAME:可从第一次登录返回的ChallengeParameters.USER_ID_FOR_SRP中提取,建议前端跳转验证码页时携带该值,再传给后端。SMS_MFA_CODE:用户输入的6位短信验证码。
- 会话有效性:
Session是一次性且有有效期的临时值,必须使用initiateAuth返回的原始会话,不能篡改或复用过期会话。
修正signInUser的职责问题
你的signInUser方法直接在服务层调用res.send,不符合分层设计原则,建议改为通过回调传递数据,由控制器层处理响应:
async signInUser(username, password, cb) { const params = { AuthFlow: "USER_PASSWORD_AUTH", ClientId: this.clientId, AuthParameters: { USERNAME: username, PASSWORD: password, SECRET_HASH: this.generateHash(username) } }; try { this.cognitoIdentity.initiateAuth(params, (err, data) => { if (err) { console.log("signinUser error:", err); cb(err); } else { cb(null, data); // 把结果传给控制器,由控制器决定如何响应前端 } }); } catch (error) { console.log("signinUser exception:", error); cb(error); } }
完整流程回顾
- 用户输入用户名密码,前端调用后端登录接口,后端触发
initiateAuth请求。 - 若用户启用了SMS_MFA,Cognito返回
ChallengeName: "SMS_MFA"及Session、ChallengeParameters。 - 后端将这些数据返回给前端,前端跳转至验证码输入页。
- 用户输入验证码后,前端将
Session、username(从ChallengeParameters.USER_ID_FOR_SRP获取)、userCode传给后端验证接口。 - 后端调用
respondToAuthChallenge完成验证,成功后返回令牌给前端,前端跳转至仪表盘。
内容的提问来源于stack exchange,提问作者micronyks
相关产品推荐
相关产品推荐

