Amplify 的 completeNewPassword 方法为用户数据抛出 TypeError

Amplify's completeNewPassword method throwing TypeError for user data

我正在尝试将自定义 UI 与 aws Amplify 结合使用,但 运行 遇到 Auth.completeNewPassword 的问题。任何尝试使用此方法都会引发错误 Error in v-on handler: "TypeError: Cannot read property 'username' of null.

在此之前使用过给定的 UI,我知道当管理员创建 Cognito 用户时,他们会在首次登录时被发送到 'new password' 表单。但是,Amplify 文档中的示例在发现用户需要新密码后立即调用 completeNewPassword 方法的 signIn 方法。

以下片段直接来自亚马逊的文档:

import { Auth } from 'aws-amplify';

Auth.signIn(username, password)
.then(user => {
    if (user.challengeName === 'NEW_PASSWORD_REQUIRED') {
        const { requiredAttributes } = user.challengeParam; // the array of required attributes, e.g ['email', 'phone_number']
        Auth.completeNewPassword(
            user,               // the Cognito User Object
            newPassword,       // the new password
            // OPTIONAL, the required attributes
            {
              email: 'xxxx@example.com',
              phone_number: '1234567890'
            }
        ).then(user => {
            // at this time the user is logged in if no MFA required
            console.log(user);
        }).catch(e => {
          console.log(e);
        });
    } else {
        // other situations
    }
}).catch(e => {
    console.log(e);
});

我已经尝试用几种不同的方法来执行此操作,但结果都是相同的 TypeError。我是否单独调用 completeNewPassword 方法、将用户存储为变量并将其传入、尝试重新登录并将该用户传递给 completeNewPassword 等都没有关系。每次都出现相同的 TypeError。

例如,以下方法将在第一次单击登录按钮时正确记录 'user' 对象,但在尝试提交新密码时单击同一按钮时会在该行之前失败。

signIn () {
    Auth.signIn(this.user_name, this.password)
    .then(user => {
        if (user.challengeName === 'NEW_PASSWORD_REQUIRED') {
        console.log(user)
        const { requiredAttributes } = user.challengeParam;
        this.$parent.$parent.pageStatus.passwordSetPanel = true;
        Auth.completeNewPassword(
            user,
            this.newPassword
        )
        }
    })
},

附加信息:

  1. 框架是 Vue
  2. 能够使用给定的 UI
  3. 为新用户确认新密码
  4. 'username' TypeError 不是来自我的 js,而是指用户承诺中的用户名参数(我已经检查过并且没有尝试将 user_name 传递到需要用户名的地方)

编辑

设法使用以下代码找到一个半工作的解决方案:

signIn () {
    this.$parent.$parent.pageStatus.loginPanel = false;
    this.$parent.$parent.loading = true;
    Auth.signIn(this.user_name, this.password)
    .then(async user => {
        if (user.challengeName === 'NEW_PASSWORD_REQUIRED') {
        const loggedUser = await Auth.completeNewPassword(
            user,
            this.password,
        )
        this.$parent.$parent.pageStatus.passwordSetPanel = true
        }
    })
}

这设法更新了用户,但我必须将密码设置为 this.password(原始的,待更改的密码)才能使其正常工作。看起来问题是 Amplify 希望我使用相同的功能来登录和调用 completeNewPassword。但是这些 UI 需要在两个不同的面板之间拆分。

这是一个非常糟糕的 hack,但我最终找到了一个解决方法,将用户承诺、名称和明文密码存储在一个临时的 js 变量中,以便为 completeNewPassword 面板保留它们。如果有人知道更好的解决方案,请随时post。

我设法使用 RxJS BehaviorSubject 解决了这个问题。

您可以查看 BehaviourSubject 的典型行为示例

正在声明 BehaviorSubject:BehaviorSubject 的初始值为 null。

congitoUser = new BehaviorSubject(null);

正在订阅来自 Auth.SignIn(认知用户)的值 return。

 login(user: { username: string; password: string }) {
    Auth.signIn(user)
      .then((data) => {
        this.congitoUser.next(data);
        if (user) {
          if (data.challengeName === 'NEW_PASSWORD_REQUIRED') {
            this.router.navigateByUrl('/change-password');
          } else {
            this.router.navigateByUrl('/home');
          }
        }
      });
  }

现在订阅会 return 更正 Cognito 用户的值。

updatePassword(password: string) {
// subscribe to cognito user (behaviour subject) and use the value it returned.
    this.congitoUser.subscribe((value) => {
      Auth.completeNewPassword(value, password, [])
        .then((data) => {
         console.log(data);
        })
        .catch((err) => console.error('Error', err));
    });
}

React/NextJs 示例

我试图在我的登录页面中这样做。获得临时密码的新注册用户无法使用它登录,需要重设密码。所以我为它生成了一个新页面。步骤:

  • 当用户尝试登录时,如果错误消息是 NEW_PASSWORD_REQUIRED,请将带有查询参数(电子邮件、临时密码)的用户发送到重置密码页面
const user = await Auth.signIn(values.email, values.password);
console.log(user)

if (user) {
  if (user.challengeName === 'NEW_PASSWORD_REQUIRED') {
    dispatch(setLoading(false));

    Router.push({
      pathname: '/reset-password',
      query: {email: JSON.stringify(values.email), password: JSON.stringify(values.password)}
    }, '/reset-password');
  }
}
  • 在密码重置页面中,获取查询参数作为状态值
const [email, setEmail] = useState<any>(null);
const [password, setPassword] = useState<any>(null);

useEffect(() => {
  setEmail(JSON.parse(props.router.query.email));
  setPassword(JSON.parse(props.router.query.password));
}, [props.router.query.email, props.router.query.password]);
  • 当用户使用新密码提交表单时,再次调用该函数
Auth.signIn(email, password)
  .then(async user => {
    if (user.challengeName === 'NEW_PASSWORD_REQUIRED') {
      const loggedUser = await Auth.completeNewPassword(user, values.proposedPassword);
      console.log(loggedUser);

      Successful({ title: 'Success', message: 'You have successfully reset your password. Redirecting..' });
    }
                        
    else {
                            
    }
});