【问题标题】:How can we reset a Cognito User's password without using Cognito's forgot password flow?我们如何在不使用 Cognito 的忘记密码流程的情况下重置 Cognito 用户的密码?
【发布时间】:2021-05-04 22:40:59
【问题描述】:

我正在使用 node.js 和 AWS Lambda 开发一个无服务器项目。 对于身份验证,我使用的是 AWS Cognito。 (前端是 AWS Amplify 上的 Vue.js 中的网络应用程序)。

我想编写自己的实现来重置忘记密码的用户的密码。

基本上,最终用户使用他们的电子邮件填写表格。如果系统中有电子邮件,我会向他们发送一个重置链接(我在数据库中设置了一个唯一代码)。

我知道Cognito's Forgot Password flow 以及一个解决方案,在该解决方案中我可以捕获 Cognito 的“电子邮件发送”代码并使用我自己的模板覆盖电子邮件,并在提到的 URL 中传递代码here。

我偶然发现了 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::*

(一旦可行,我将微调权限)

以下是我收到的错误消息。 我开始觉得我做这件事的方法不是推荐的做事方式。

用户:arn:aws:sts::[XXXXXXX]:assumed-role/[YYYYYYYYY]-us-east-1-lambdaRole/web-app-service-dev-resetPassword 无权执行:cognito-idp :AdminSetUserPassword 资源:arn:aws:cognito-idp:us-east-1:[[XXXXXXX]]:userpool/us-east-1_ZZZZZZZZ

(Serverless 可以访问我的 AWS 访问密钥,并且对 * 资源具有 * 权限——所以我认为我没有遗漏任何权限)。

我的问题:

  • 这是推荐的方法吗?
  • 我是否可以配置权限,使我的 lambda 函数具有执行此操作所需的权限?

【问题讨论】:

  • 你有什么解决办法吗?
  • @SushantSomani 我在下面分享了我的解决方案。感谢您的检查。我忘了我在 Stack Overflow 上问过。如果您有任何疑问,请告诉我。

标签: aws-lambda amazon-cognito


【解决方案1】:

事实证明,您需要使用 Amplify API 而不是 Cognito API。 这包括几个步骤:

1.为身份验证配置 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),
  };
}

【讨论】:

    猜你喜欢
    • 2018-02-22
    • 2022-08-13
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    • 2020-09-14
    • 1970-01-01
    • 1970-01-01
    • 2016-11-01
    相关资源
    最近更新 更多