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

AWS Cognito SMS 2FA报错:无效验证码或用户认证状态异常

解决AWS Cognito SMS 2FA认证的两个异常问题

我来帮你梳理下这两个错误的根源,以及对应的修复方案:

问题1:「Missing required parameter SMS_MFA_CODE」错误

这个错误的核心原因很直接:当mfaRequired回调触发时,你立刻调用了cognitoUser.sendMFACode(context.state.code, this),但此时用户还没来得及输入验证码,context.state.code是空字符串,Cognito自然会提示缺少必要参数。

你不需要在mfaRequired里马上提交验证码,这个回调的作用只是通知你需要显示验证码输入框,让用户输入收到的短信验证码。

问题2:「Invalid code or auth state for the user」错误

当Cognito返回mfaRequired后,当前的cognitoUser实例已经处于MFA验证的会话状态中。你此时再次调用authenticateUser会重置整个认证流程,破坏了之前的MFA上下文,导致Cognito无法识别当前的认证状态,所以抛出这个错误。

正确的做法是复用同一个cognitoUser实例,在用户输入验证码后直接调用sendMFACode完成验证,而不是重新走一遍登录流程。


修改后的完整代码

下面是调整后的React组件代码,我标记了关键修改点:

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, Redirect } from "react-router-dom";
import * as AWS from 'aws-sdk/global';
import { AuthenticationDetails, CognitoUserPool, CognitoUserAttribute, CognitoUser } from 'amazon-cognito-identity-js';
import PropTypes from 'prop-types';
import '../../stylesheets/Authentication.css';

export default class CognitoIdentitySignIn extends Component {
  constructor(props) {
    super(props);
    this.state = {
      password: "",
      email: "",
      code: "",
      submissionAnnouncement: "",
      readyForCode: false
    };
    // 关键修改1:保存cognitoUser实例到组件属性,方便后续复用
    this.cognitoUser = null;
    this.handleChangeEmail = this.handleChangeEmail.bind(this);
    this.handleChangePassword = this.handleChangePassword.bind(this);
    this.handleChangeCode = this.handleChangeCode.bind(this);
    this.submitCredentials = this.submitCredentials.bind(this);
    // 关键修改2:新增提交验证码的方法
    this.submitCode = this.submitCode.bind(this);
  }

  handleChangeEmail(event) {
    this.setState({email: event.target.value});
  }

  handleChangePassword(event) {
    this.setState({password: event.target.value});
  }

  handleChangeCode(event) {
    this.setState({code: event.target.value});
  }

  submitCredentials(event) {
    this.signIn(this, this.state.email, this.state.password);
  }

  // 关键修改3:提交验证码的方法,复用之前的cognitoUser实例
  submitCode() {
    if (!this.cognitoUser || !this.state.code) {
      this.setState({ submissionAnnouncement: "请先输入验证码" });
      return;
    }
    this.cognitoUser.sendMFACode(this.state.code, {
      onSuccess: (session) => {
        var accessToken = session.getAccessToken().getJwtToken();
        AWS.config.region = 'us-west-2';
        var Logins = {}
        Logins[`cognito-idp.${AWS.config.region}.amazonaws.com/${'us-west-2_xxxxxxxx'}`] = accessToken;
        AWS.config.credentials = new AWS.CognitoIdentityCredentials({
          IdentityPoolId : 'us-west-2:XXXXXXX-XXXX-XXXXXXXX',
          Logins : Logins
        });
        AWS.config.credentials.refresh((error) => {
          if (error) {
            alert('onSuccess:\n' + JSON.stringify(error));
            this.setState({ submissionAnnouncement: error.message, readyForCode: false })
            console.error(error);
          } else {
            this.setState({ submissionAnnouncement: "SUCCESS", readyForCode: false });
            console.log(session);
          }
        });
      },
      onFailure: (err) => {
        alert('MFA验证失败:\n' + JSON.stringify(err));
        this.setState({ submissionAnnouncement: err.message })
      }
    });
  }

  signIn(context, email, password) {
    var authenticationData = {
      Username : email,
      Password : password
    };
    var authenticationDetails = new AuthenticationDetails(authenticationData);
    var poolData = {
      UserPoolId: 'us-west-2_xxxxxxxx',
      ClientId: 'XXXXXXXXXXXXXXXXXXXXXX',
    };
    var userPool = new CognitoUserPool(poolData);
    var userData = {
      Username : email,
      Pool : userPool
    };
    // 关键修改4:把cognitoUser实例保存到组件属性
    this.cognitoUser = new CognitoUser(userData);
    console.log(authenticationDetails);
    console.log(this.cognitoUser);
    this.cognitoUser.authenticateUser(authenticationDetails, {
      onSuccess: function (session) {
        var accessToken = session.getAccessToken().getJwtToken();
        AWS.config.region = 'us-west-2';
        var Logins = {}
        Logins[`cognito-idp.${AWS.config.region}.amazonaws.com/${poolData.UserPoolId}`] = accessToken;
        AWS.config.credentials = new AWS.CognitoIdentityCredentials({
          IdentityPoolId : 'us-west-2:XXXXXXX-XXXX-XXXXXXXX',
          Logins : Logins
        });
        AWS.config.credentials.refresh((error) => {
          if (error) {
            alert('onSuccess:\n' + JSON.stringify(error));
            context.setState({ submissionAnnouncement: error.message, readyForCode: false })
            console.error(error);
          } else {
            context.setState({ submissionAnnouncement: "SUCCESS", readyForCode: false });
            console.log(session);
          }
        });
      },
      onFailure: function(err) {
        alert('登录失败:\n' + JSON.stringify(err));
        context.setState({ submissionAnnouncement: err.message, readyForCode: false })
      },
      mfaRequired: function(codeDeliveryDetails) {
        console.log(codeDeliveryDetails)
        // 关键修改5:这里只更新UI,让用户输入验证码,不调用sendMFACode
        context.setState({ submissionAnnouncement: "请输入短信验证码", readyForCode: true })
      }
    });
  }

  render() {
    return (
      <div className='SignIn'>
        <div className='sign-in-input-box'>
          <label>
            <p>Email</p>
            <input className='sign-in-email-input' value={this.state.email} onChange={this.handleChangeEmail} type='text' />
          </label>
        </div>
        <div className='sign-in-input-box'>
          <label>
            <p>Password</p>
            <input className='sign-in-password-input' value={this.state.password} onChange={this.handleChangePassword} type='password' />
          </label>
        </div>
        <div className="click-text" onClick={this.submitCredentials}>
          SIGN IN
        </div>
        {(this.state.submissionAnnouncement === "" ? null : <div><span>{this.state.submissionAnnouncement}</span></div>)}
        {(this.state.readyForCode) ? (
          <div className='sign-in-input-box'>
            <label>
              <p>SMS验证码</p>
              <input className='sign-in-code-input' value={this.state.code} onChange={this.handleChangeCode} type='text' />
            </label>
            {/* 关键修改6:添加提交验证码的按钮 */}
            <div className="click-text" onClick={this.submitCode}>
              提交验证码
            </div>
          </div>
        ): null}
      </div>
    )
  }
}

CognitoIdentitySignIn.propTypes = { }

关键修复总结

  1. 保存cognitoUser实例:把登录时创建的cognitoUser存在组件属性里,避免MFA阶段重新创建实例导致会话丢失。
  2. 拆分登录和MFA验证流程:登录触发mfaRequired后,只显示验证码输入框,等用户输入后再调用sendMFACode提交。
  3. 避免重复调用authenticateUser:MFA阶段不需要重新走登录流程,直接用已有的cognitoUser实例完成验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:53:28