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
)
}
})
},
附加信息:
- 框架是 Vue
- 能够使用给定的 UI
为新用户确认新密码
- '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 {
}
});
我正在尝试将自定义 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
)
}
})
},
附加信息:
- 框架是 Vue
- 能够使用给定的 UI 为新用户确认新密码
- '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 {
}
});