我们如何在不使用 Cognito 的忘记密码流程的情况下重置 Cognito 用户的密码?
How can we reset a Cognito User's password without using Cognito's forgot password flow?
我正在使用 node.js 和 AWS Lambda 开发无服务器项目。
对于身份验证,我使用的是 AWS Cognito。 (前端是 AWS Amplify 上 Vue.js 中的一个网络应用程序)。
我想编写自己的实现来重置忘记密码的用户的密码。
基本上,最终用户使用他们的电子邮件填写表格。如果电子邮件在系统中,我会向他们发送重置 link(它具有我在数据库中设置的唯一代码)。
我知道 Cognito's Forgot Password flow and also a solution in which I can capture Cognito's "email sending" code and over-ride the email with my own template passing the code in the URL mentioned 。
我偶然发现了 adminSetUserPassword
API,我确信它会起作用——但无论我做什么,我的 lambda 函数都没有获得执行此操作的权限。
这是我的 nodejs 代码:
import AWS from 'aws-sdk';
const COGNITO_POOL_ID = process.env.COGNITO_USERPOOL_ID;
const csp = new AWS.CognitoIdentityServiceProvider();
export async function resetUserPassword(username, newPassword) {
// Constructing request to send to Cognito
const params = {
Password: newPassword,
UserPoolId: COGNITO_POOL_ID,
Username: username,
Permanent: true,
};
await csp.adminSetUserPassword(params).promise();
return true;
}
这是我对 lambda 函数的 IAM 权限(它是无服务器 yml 格式):
CognitoResetPasswordIAM:
Effect: Allow
Action:
- cognito-idp:*
Resource:
- arn:aws:cognito-idp:us-east-1::*
(一旦成功,我会微调权限)
以下是我收到的错误信息。
我开始觉得我这样做的方法不是推荐的做事方式。
User: arn:aws:sts::[XXXXXXX]:assumed-role/[YYYYYYYYY]-us-east-1-lambdaRole/web-app-service-dev-resetPassword is not authorized to perform: cognito-idp:AdminSetUserPassword on resource: arn:aws:cognito-idp:us-east-1:[[XXXXXXX]]:userpool/us-east-1_ZZZZZZZZ
(Serverless 可以使用对 * 资源的 * 权限访问我的 AWS 访问密钥——所以我不认为我在那里缺少任何权限)。
我的问题:
- 这是推荐的方法吗?
- 我是否可以配置权限,使我的 lambda 函数具有执行此操作所需的权限?
事实证明,您需要使用 Amplify API 而不是 Cognito API。
这涉及几个步骤:
1.为 Auth 配置您的 Cognito Amplify 服务。
import Amplify, { Auth } from 'aws-amplify';
export function configureCognitoAuth() {
Amplify.configure({
Auth: {
region: process.env.COGNITO_REGION,
userPoolId: process.env.COGNITO_USERPOOL_ID,
mandatorySignIn: false,
userPoolWebClientId: process.env.COGNITO_CLIENT_ID,
authenticationFlowType: 'USER_PASSWORD_AUTH',
oauth: {
domain: process.env.COGNITO_APP_DOMAIN,
scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
responseType: 'code', // or 'token', note that REFRESH token will only be generated when the responseType is code
},
},
});
// You can get the current config object
Auth.configure();
}
2。调用Auth.forgotPassword服务将实际密码发送到这里
import { Auth } from 'aws-amplify';
async function sendUserPasswordResetEmail(event) {
// Any validation checks, rate limits you want to check here, etc.
try {
configureCognitoAuth();
await Auth.forgotPassword(userId);
} catch (error) {
// An error occurred while sending the password reset email
}
}
3。写一个 forgotPasswordEmailTrigger Cognito Hook
这会将默认的 Cognito 重置密码电子邮件替换为您自己的自定义电子邮件。
这也是一个 lamdba 方法,您需要将其附加到 Cognito 自定义消息触发器(从 Cognito > 常规设置 > 触发器)
我的代码如下所示:
async function forgotPasswordEmailTrigger(event, context, callback) {
// Confirm it is a PreSignupTrigger
if (event.triggerSource === 'CustomMessage_ForgotPassword') {
const { userName } = event;
const passwordCode = event.request.codeParameter;
const resetUrl = `${BASE_URL}/password_reset/${userName}/${passwordCode}`;
let message = 'Your HTML email template goes here';
message = message
.replace(/{{passwordResetLink}}/g, resetUrl);
event.response.emailSubject = 'Email Subject here';
event.response.emailMessage = message;
}
// Return to Amazon Cognito
callback(null, event);
}
event.request.codeParameter
是代码从 Cognito 返回的地方。我认为有办法改变这一点,但我没有费心。我在下一步中使用相同的代码进行验证。
4。当密码重置请求发送到您的后端时,从 Amplify Auth 服务调用 forgotPasswordSubmit 方法
当用户点击 URL 时,他们来到网站,我从 URL 中获取代码和用户 ID(来自第 3 步),然后验证代码 + 重置密码如下:
async function resetPassword(event) {
const { token, password, user_id } = event.body;
// Do your validations & checks
// Getting to here means everything is in order. Reset the password
try {
configureCognitoAuth(); // See step 1
await Auth.forgotPasswordSubmit(user_id, token, password);
} catch (error) {
// Error occurred while resetting the password
}
const result = {
result: true,
};
return {
statusCode: 200,
body: JSON.stringify(result),
};
}
我正在使用 node.js 和 AWS Lambda 开发无服务器项目。 对于身份验证,我使用的是 AWS Cognito。 (前端是 AWS Amplify 上 Vue.js 中的一个网络应用程序)。
我想编写自己的实现来重置忘记密码的用户的密码。
基本上,最终用户使用他们的电子邮件填写表格。如果电子邮件在系统中,我会向他们发送重置 link(它具有我在数据库中设置的唯一代码)。
我知道 Cognito's Forgot Password flow and also a solution in which I can capture Cognito's "email sending" code and over-ride the email with my own template passing the code in the URL mentioned
我偶然发现了 adminSetUserPassword
API,我确信它会起作用——但无论我做什么,我的 lambda 函数都没有获得执行此操作的权限。
这是我的 nodejs 代码:
import AWS from 'aws-sdk';
const COGNITO_POOL_ID = process.env.COGNITO_USERPOOL_ID;
const csp = new AWS.CognitoIdentityServiceProvider();
export async function resetUserPassword(username, newPassword) {
// Constructing request to send to Cognito
const params = {
Password: newPassword,
UserPoolId: COGNITO_POOL_ID,
Username: username,
Permanent: true,
};
await csp.adminSetUserPassword(params).promise();
return true;
}
这是我对 lambda 函数的 IAM 权限(它是无服务器 yml 格式):
CognitoResetPasswordIAM:
Effect: Allow
Action:
- cognito-idp:*
Resource:
- arn:aws:cognito-idp:us-east-1::*
(一旦成功,我会微调权限)
以下是我收到的错误信息。 我开始觉得我这样做的方法不是推荐的做事方式。
User: arn:aws:sts::[XXXXXXX]:assumed-role/[YYYYYYYYY]-us-east-1-lambdaRole/web-app-service-dev-resetPassword is not authorized to perform: cognito-idp:AdminSetUserPassword on resource: arn:aws:cognito-idp:us-east-1:[[XXXXXXX]]:userpool/us-east-1_ZZZZZZZZ
(Serverless 可以使用对 * 资源的 * 权限访问我的 AWS 访问密钥——所以我不认为我在那里缺少任何权限)。
我的问题:
- 这是推荐的方法吗?
- 我是否可以配置权限,使我的 lambda 函数具有执行此操作所需的权限?
事实证明,您需要使用 Amplify API 而不是 Cognito API。 这涉及几个步骤:
1.为 Auth 配置您的 Cognito Amplify 服务。
import Amplify, { Auth } from 'aws-amplify';
export function configureCognitoAuth() {
Amplify.configure({
Auth: {
region: process.env.COGNITO_REGION,
userPoolId: process.env.COGNITO_USERPOOL_ID,
mandatorySignIn: false,
userPoolWebClientId: process.env.COGNITO_CLIENT_ID,
authenticationFlowType: 'USER_PASSWORD_AUTH',
oauth: {
domain: process.env.COGNITO_APP_DOMAIN,
scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
responseType: 'code', // or 'token', note that REFRESH token will only be generated when the responseType is code
},
},
});
// You can get the current config object
Auth.configure();
}
2。调用Auth.forgotPassword服务将实际密码发送到这里
import { Auth } from 'aws-amplify';
async function sendUserPasswordResetEmail(event) {
// Any validation checks, rate limits you want to check here, etc.
try {
configureCognitoAuth();
await Auth.forgotPassword(userId);
} catch (error) {
// An error occurred while sending the password reset email
}
}
3。写一个 forgotPasswordEmailTrigger Cognito Hook 这会将默认的 Cognito 重置密码电子邮件替换为您自己的自定义电子邮件。
这也是一个 lamdba 方法,您需要将其附加到 Cognito 自定义消息触发器(从 Cognito > 常规设置 > 触发器)
我的代码如下所示:
async function forgotPasswordEmailTrigger(event, context, callback) {
// Confirm it is a PreSignupTrigger
if (event.triggerSource === 'CustomMessage_ForgotPassword') {
const { userName } = event;
const passwordCode = event.request.codeParameter;
const resetUrl = `${BASE_URL}/password_reset/${userName}/${passwordCode}`;
let message = 'Your HTML email template goes here';
message = message
.replace(/{{passwordResetLink}}/g, resetUrl);
event.response.emailSubject = 'Email Subject here';
event.response.emailMessage = message;
}
// Return to Amazon Cognito
callback(null, event);
}
event.request.codeParameter
是代码从 Cognito 返回的地方。我认为有办法改变这一点,但我没有费心。我在下一步中使用相同的代码进行验证。
4。当密码重置请求发送到您的后端时,从 Amplify Auth 服务调用 forgotPasswordSubmit 方法
当用户点击 URL 时,他们来到网站,我从 URL 中获取代码和用户 ID(来自第 3 步),然后验证代码 + 重置密码如下:
async function resetPassword(event) {
const { token, password, user_id } = event.body;
// Do your validations & checks
// Getting to here means everything is in order. Reset the password
try {
configureCognitoAuth(); // See step 1
await Auth.forgotPasswordSubmit(user_id, token, password);
} catch (error) {
// Error occurred while resetting the password
}
const result = {
result: true,
};
return {
statusCode: 200,
body: JSON.stringify(result),
};
}