You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Node架构下AWS Cognito MFA后端认证实现问询

解决AWS Cognito MFA重复发送短信的问题

我完全懂你的痛点——用cognitoUser.authenticateUser时,后端没法直接收集用户的MFA验证码,只能把状态抛给前端,等用户输入后再回调,结果导致Cognito发了两次短信。换成initiateAuth确实是更合适的方案,它能把认证流程拆成明确的两步,完全避免重复发验证码的问题。

问题根源

原来的authenticateUser方法在触发mfaRequired回调时,已经让Cognito发送了一次验证码。当你把这个状态返回前端,用户输入验证码后再调用sendMFACode,Cognito会把这次操作当成新的MFA请求,所以又发了一次短信。而initiateAuth+respondToAuthChallenge的组合,可以让我们在第一步触发MFA并获取会话标识,第二步只用这个会话标识去验证验证码,不会触发新的短信发送。

修改后的后端实现

我们需要拆成两个API接口:一个用于初始的账号密码认证,触发MFA并返回会话信息;另一个用于接收用户输入的验证码,完成最终认证。

1. 初始认证接口(触发MFA)

AWS.config.update({ region: process.env.Region });
const { CognitoIdentityServiceProvider } = require('aws-sdk');
const cognitoISP = new CognitoIdentityServiceProvider();

router.post('/api/initiate-auth', async (req, res) => {
  const { user, pass } = req.body.value;
  
  try {
    const params = {
      AuthFlow: 'USER_PASSWORD_AUTH',
      ClientId: process.env.ClientId,
      AuthParameters: {
        USERNAME: user,
        PASSWORD: pass
      }
    };
    
    const response = await cognitoISP.initiateAuth(params).promise();
    
    // 如果触发MFA,返回会话信息和验证码发送详情
    if (response.ChallengeName === 'SMS_MFA') {
      return res.json({
        status: 'MFA_REQUIRED',
        session: response.Session,
        codeDeliveryDetails: response.ChallengeParameters.CodeDeliveryDetails,
        username: user // 把用户名一起返回给前端,方便后续请求
      });
    }
    
    // 如果不需要MFA,直接返回token
    res.json({
      status: 'SUCCESS',
      accessToken: response.AuthenticationResult.AccessToken,
      idToken: response.AuthenticationResult.IdToken
    });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

2. MFA验证接口(完成认证)

router.post('/api/verify-mfa', async (req, res) => {
  const { session, verificationCode, username } = req.body;
  
  try {
    const params = {
      ChallengeName: 'SMS_MFA',
      ClientId: process.env.ClientId,
      Session: session,
      ChallengeResponses: {
        USERNAME: username,
        SMS_MFA_CODE: verificationCode
      }
    };
    
    const response = await cognitoISP.respondToAuthChallenge(params).promise();
    
    res.json({
      accessToken: response.AuthenticationResult.AccessToken,
      idToken: response.AuthenticationResult.IdToken
    });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

关键细节说明

  • 会话标识Session:这个值是Cognito在第一步返回的,必须在第二步请求中传递,它代表当前未完成的认证会话,Cognito会基于这个会话验证验证码,不会重新发送短信。
  • 用户名传递:在verify-mfa接口中,ChallengeResponses需要包含USERNAME,让前端在第二步请求时一起传递是最直接的方式,避免额外解析Session的复杂度。
  • 完全后端控制:整个认证逻辑都在后端执行,前端只负责收集用户输入和传递数据,完全符合你不想把认证逻辑放在前端的需求。

前端配合流程

  1. 前端调用/api/initiate-auth,传入账号密码。
  2. 如果返回MFA_REQUIRED,显示验证码输入框,同时保存session和用户名。
  3. 用户输入验证码后,前端调用/api/verify-mfa,传入session、用户名和验证码。
  4. 后端返回token,前端完成登录流程。

这样操作下来,Cognito只会在第一步触发MFA时发送一次短信,完美解决重复发送的问题。

内容的提问来源于stack exchange,提问作者 rio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 06:34:55