简体   繁体   English

React 和 AWS Amplify - 用户没有将传递配置设置为打开 SMS_MFA

[英]React & AWS Amplify - User does not have delivery config set to turn on SMS_MFA

I have a React web application (utilizing aws-amplify) which is connecting to AWS Cognito User Pool for authentication.我有一个 React web 应用程序(使用 aws-amplify),它连接到 AWS Cognito 用户池进行身份验证。

User of my application can optionally enable SMS MFA from settings.我的应用程序的用户可以选择从设置中启用 SMS MFA。

I tried to enable SMS MFA using aws amplify npm package but I'm facing an error saying我尝试使用aws amplify npm package启用 SMS MFA,但我遇到一个错误说

{
  "__type": "InvalidParameterException",
  "message": "User does not have delivery config set to turn on SMS_MFA"
}

I have set MFA to "Optional" on AWS Cognito User Pools settings as seen in the screenshot below.我已在 AWS Cognito 用户池设置中将 MFA 设置为“可选”,如下面的屏幕截图所示。

在此处输入图像描述

And here's my component logic这是我的组件逻辑

import React, { useState, useEffect } from 'react';
import { Card, Grid, Typography, Box, Switch } from '@material-ui/core';
import { Auth } from 'aws-amplify';

const Profile = () => {
  const [currentUser, setCurrentUser] = useState(null);

  // use this state to highlight MFA status
  const [isMFAEnabled, setIsMFAEnabled] = useState(false);

  const toggleMFA = async () => {
    const preferredMFA = isMFAEnabled ? 'NOMFA' : 'SMS';
    try {
        const result = await Auth.setPreferredMFA(currentUser, preferredMFA);
        setIsMFAEnabled(!isMFAEnabled);
        // Auth.enableSMS(currentUser);
    } catch (error) {
        console.log('error :: ', error);
    }
  };

  useEffect(() => {
    async function fetchProfileData() {
      const user = await Auth.currentAuthenticatedUser();
      setCurrentUser(user);
      
      // enable or disabled MFA switch
      const { preferredMFA } = user;
      setIsMFAEnabled(!(preferredMFA && preferredMFA === 'NOMFA'));
    }

    fetchProfileData();
  }, []);

  return (
    <>
      <Grid
        container
        direction="row"
        justifyContent="center"
        alignItems="center"
      >
        <Grid item xs={12} sm={12} md={10} lg={8} xl={6}>
            <Card>
                <Typography variant="h4">Security</Typography>
                <Box
                    display="flex"
                    flexDirection="row"
                    alignItems="center"
                >
                    <Typography variant="subtitle">
                        Two factor authentication
                    </Typography>
                    <Switch
                        checked={isMFAEnabled}
                        onChange={toggleMFA}
                        name="MFA"
                    />
                </Box>
            </Card>
        </Grid>
      </Grid>
    </>
  );
};

export default Profile;

I got this error too and it took me a while to figure out what was wrong我也遇到了这个错误,我花了一段时间才弄清楚出了什么问题

My Cognito's configuration:我的 Cognito 的配置:

  • Using custom messages trigger lambda , users are invited to sign-up after they receive an email使用自定义消息触发 lambda ,用户在收到 email 后被邀请注册
  • TOTP is enabled (let's ignore this for now) TOTP 已启用(我们暂时忽略它)
  • SMS is enabled短信已启用
  • Attribute verification is set to No Verification属性验证设置为No Verification

This is how I solved the issue:这就是我解决问题的方法:

First, I used AWS CLI to reproduce the steps to onboard users:首先,我使用 AWS CLI 向板载用户重现这些步骤:

  1. Admin creates a new user管理员创建新用户
aws cognito-idp admin-create-user \
--user-pool-id <user-pool-id> \
--username <user_email> \
--user-attributes Name="email",Value="<user_email>" Name="name",Value="Alice" Name="family_name",Value="Doe" Name="email_verified",Value="true" \
--force-alias-creation \
--temporary-password "LongSecret132@" \
--desired-delivery-mediums "EMAIL" \
--profile <aws_config_profile>
  1. A CustomMessage_AdminCreateUser is triggered synchronouly , if lambda succeeds the user receives an email with a link to complete sing-up.一个 CustomMessage_AdminCreateUser 被同步触发,如果 lambda 成功,用户会收到一个 email 与一个链接来完成唱歌。

This is why I create users with --desired-delivery-mediums "EMAIL" , above这就是为什么我使用--desired-delivery-mediums "EMAIL"创建用户的原因

  1. The frontend would route the user to the correct UI前端会将用户路由到正确的 UI
  2. The user has to set a password, otherwise the user would remain in FORCE_CHANGE_PASSWORD status用户必须设置密码,否则用户将保持FORCE_CHANGE_PASSWORD状态
aws cognito-idp admin-set-user-password --user-pool-id <user-pool-id> --username <user_email> --password "NewSecret@111" --permanent --profile <aws_config_profile>
  1. The user has to set a phone number.用户必须设置一个电话号码。 Done now because they aren't asked before step 1. If you want you could ask before and set the Name="phone_number",Value="<user_phone_number>" and Name="phone_number_verified",Value="true" in step 1.现在完成,因为在第 1 步之前没有询问他们。如果您愿意,可以在第 1 步之前询问并设置Name="phone_number",Value="<user_phone_number>"Name="phone_number_verified",Value="true" .
aws cognito-idp admin-update-user-attributes \
--user-pool-id <user-pool-id> \
--username <user_email> \
--user-attributes Name="phone_number",Value="+447000200100" Name="phone_number_verified",Value="true" \
--profile <aws_config_profile>
  1. Sequencially, the user mfa prefence needs to be set before users can authenticate themselves.依次,需要先设置用户 mfa 首选项,然后用户才能对其进行身份验证。
aws cognito-idp admin-set-user-mfa-preference \
--user-pool-id <user-pool-id> \
--username <user_email> \
--sms-mfa-settings Enabled=true,PreferredMfa=true \
--profile <aws_config_profile>

So I did this all manually and then using the UI I tried to authenticate and Cognito did send me an SMS.所以我手动完成了这一切,然后使用我尝试进行身份验证的 UI,Cognito 确实向我发送了一条短信。 And no error.并且没有错误。

My conclusion is that the error happens when the user attributes (step 5) and mfa preference (step 6) arent setup properly and in the correct order.我的结论是,当用户属性(第 5 步)和 mfa 首选项(第 6 步)没有按正确顺序正确设置时,就会发生错误。

You can try the commands above with a test user.您可以使用测试用户尝试上述命令。

Second, Amplify docs were useful.其次, Amplify 文档很有用。 The React code could do something like: React 代码可以执行以下操作:

  1. Cosinder:考辛德:
  • the api created the user (steps 1). api 创建了用户(步骤 1)。
  • the user set their new password (steps 2 to 4)用户设置他们的新密码(步骤 2 到 4)
  • the api registered the user's phone number (step 5) api 注册用户的电话号码(步骤5)

All you are left with is handling the MFA either for the first time or after,剩下的就是第一次或之后处理 MFA,

const fetchCognitoUser = async (flag = false) => {
  const user = await Auth.currentAuthenticatedUser({
    bypassCache: flag,
  });
  return user;
};

const handleMfaAuth = async ({ userObject, mfaToken }) => {
    try {
      // when MFA is being setup the first time
      // checks if this does not exist because
      // setting mfa to optional in cognito will not give you a challengeName
      if (!userObject.challengeName) {
        await Auth.verifyTotpToken(userObject, mfaToken);
        
        // This would be step 6 in the CLI version above.
        await Auth.setPreferredMFA(userObject, 'SMS');
        
        const cognitoUser = await fetchCognitoUser().catch((err) => {
          console.error(err);
        });

        if (cognitoUser) {
          // any logic to ensure correct Authentication
          // Load apps landing page.
        }
      }
      // when the user enters the MFA token
      else if (userObject.challengeName === 'SMS_MFA') {
        await Auth.confirmSignIn(userObject, mfaToken, 'SMS_MFA');
        const cognitoUser = await fetchCognitoUser().catch((err) => {
          console.error(err);
        });

        if (cognitoUser) {
          // any logic to ensure correct Authentication
          // Load apps landing page.
        }
      }
    } catch (error) {
      // Token is not verified
      setShowError(true);
    }
  };
  1. Say the user credentials are set but their MFA got deactivated (eg manually in AWS Console) or they are simply performing log-in again.假设用户凭证已设置但他们的 MFA 被停用(例如在 AWS 控制台中手动)或者他们只是再次执行登录。
const handleSignIn = async ({ username, password }) => {
  try{
    const user = await Auth.signIn(username, password);
    // if MFA hasn't been setup
    // checks if this does not exist because
    // setting mfa to optional in cognito will not give you a challengeName
    if (!user.challengeName) {
      // show the page to set up MFA
      setShowSetupMfa(true);
    } else if (user.challengeName === 'SMS_MFA') {
      // If MFA is enabled, sign-in should be confirmed with the confirmation code
      const loggedUser = await Auth.confirmSignIn(
          user,   // Return object from Auth.signIn()
          code,   // Confirmation code captured in the UI
          mfaType // MFA Type e.g. SMS_MFA, SOFTWARE_TOKEN_MFA
      );
      // show the page to enter mfa token
      setShowMfa(true);
    }
  } catch (error) {
    // handle error
  }
}

Hope this helps希望这可以帮助

Make sure Cognito is correctly configured.确保 Cognito 配置正确。 You need SMS enabled, the documentation explains how to do it您需要启用 SMS, 文档说明了如何执行此操作

I must say that boto3's documentation helped me understand my options and how some things work in cognito, I definetly recommend taking a look for those of you having similar or slightly different issues.我必须说, boto3 的文档帮助我了解了我的选择以及某些事情在 cognito 中的工作原理,我绝对建议您查看那些有类似或略有不同问题的人。

You will see this MFA issue if you don't have phone_number ready.如果您没有准备好 phone_number,您将看到此 MFA 问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 AWS Amplify 基于电子邮件的 MFA - AWS Amplify Email-based MFA AWS Amplify withAuthenticator React HOC 是否必须包装根节点? Auth 可以是可选的吗? - Does the AWS Amplify withAuthenticator React HOC have to wrap the root node? Can Auth be optional? 如何使用 AWS Amplify 和 React 在注册后让用户登录 - How to sign user in after registration using AWS Amplify and React aws-amplify-react 和 nextjs 破坏了我的用户上下文 - aws-amplify-react and nextjs breaks my user context 使用React js发送SMS而不是电子邮件的aws-amplify忘记密码功能 - aws-amplify forgot password function with react js sending SMS instead of email 通过Amplify坚持使用AWS Cognito用户 - Persist AWS Cognito User with Amplify 如何在React&Java Spring中设置AWS消息队列(SMS) - How to set up AWS message queuing (SMS) in React & Java Spring 我已经在 AWS amplify 上部署了新的 React 代码,但网站上仍然看不到更改?? 如何解决这个问题? - I have deployed the new React code on AWS amplify but the changes are still not visible on the website?? How to solve this issue? 被 CORS 策略阻止“...没有 HTTP 正常状态”(Amplify 和 ReactJS、AWS Gateway 和 Lambda) - Blocked by CORS policy “…does not have HTTP ok status” (Amplify and ReactJS, AWS Gateway and Lambda) React 应用程序在本地加载图像,但 AWS Amplify 不会加载这些图像 - React app loads images locally, but AWS Amplify does not load those images
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM