Firebase:如何使用 NodeJs 发送密码重置电子邮件后端 [英] Firebase : How to send a password reset email backend with NodeJs

查看:36
本文介绍了Firebase:如何使用 NodeJs 发送密码重置电子邮件后端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用此处找到的代码:https://firebase.google.com/docs/auth/web/manage-users#send_a_password_reset_email

I'm trying to impliment the code as found here: https://firebase.google.com/docs/auth/web/manage-users#send_a_password_reset_email

var auth = firebase.auth();
var emailAddress = "user@example.com";

auth.sendPasswordResetEmail(emailAddress).then(function() {
  // Email sent.
}).catch(function(error) {
  // An error happened.
});

但我在 firebase admin 中找不到 sendPasswordResetEmail 方法.

But I can't find the sendPasswordResetEmail method in firebase admin.

无论如何我可以在后端执行此操作?

Anyway I can do this on the backend?

推荐答案

ORIGINAL JULY 2018 ANSWER:

sendPasswordResetEmail() 方法是来自客户端 auth 模块的方法,你是对的,Admin-SDK 没有 - 或者任何可比的东西.大多数人从前端调用这个函数...

The sendPasswordResetEmail() method is a method from the client-side auth module, and you're right, the Admin-SDK doesn't have it - or anything comparable. Most folks call this function from the front-end...

话虽如此,可以在后端完成……但您必须创建自己的功能.我以前做过这种事情,我会从我的云函数中粘贴一些我的代码来帮助你……你是否应该选择走这条路.我创建自己的 JWT,将其附加到 URL,然后使用 NodeMailer 向他们发送带有该链接的电子邮件......当他们访问该链接(密码重置页面)时,他们输入了他们的新密码,然后当他们点击提交按钮时,我从 URL 中提取 JWT 并将其传递给我的第二个云函数,该函数对其进行验证,然后重置他们的密码.

With that said, it is possible to accomplish on the backend... but you'll have to create your own functionality. I've done this sort of thing before, I'll paste some of my code from my cloud functions to help you along... should you choose to go down this road. I create my own JWT, append it to a URL, and then use NodeMailer to send them an email with that link... when they visit that link (a password reset page) they enter their new password, and then when they click the submit button I pull the JWT out of the URL and pass it to my 2nd cloud function, which validates it and then resets their password.

const functions = require('firebase-functions');
const admin = require('firebase-admin');
var jwt = require('jsonwebtoken');

admin.initializeApp()

// Email functionality
const nodemailer = require('nodemailer');

// Pull the gmail login info out of the environment variables
const gmailEmail = functions.config().gmail.email;
const gmailPassword = functions.config().gmail.password;

// Configure the nodemailer with our gmail info
const mailTransport = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: gmailEmail,
    pass: gmailPassword,
  },
});



// Called from any login page, from the Forgot Password popup
// Accepts a user ID - finds that user in the database and gets the associated email
// Sends an email to that address containing a link to reset their password
exports.forgotPassword = functions.https.onRequest( (req, res) => {

  // Make a query to the database to get the /userBasicInfo table... 
  admin.database().ref(`userBasicInfo`).once('value').then( dataSnapshot => {
    let allUsers = dataSnapshot.val() ? dataSnapshot.val() : {};
    let matchingUid = '';
    let emailForUser = '';

    // Loop over all of the users
    Object.keys(allUsers).forEach( eachUid => {
      // See if their email matches
      allUsers[eachUid]['idFromSis'] = allUsers[eachUid]['idFromSis'] ? allUsers[eachUid]['idFromSis'] : '';
      if (allUsers[eachUid]['idFromSis'].toUpperCase() === req.body.userIdToFind.toUpperCase()) {
        // console.log(`Found matching user! Uid: ${eachUid} with idFromSis: ${allUsers[eachUid]['idFromSis']}... setting this as the matchingUid`);
        matchingUid = eachUid;
        emailForUser = allUsers[eachUid]['email'] ? allUsers[eachUid]['email'] : '';
      }
    })

    // After loop, see if we found the matching user, and make sure they have an email address
    if (matchingUid === '' || emailForUser == '') {
      // Nothing found, send a failure response
      res.send(false);
    } else {
      // Send an email to this email address containing the link to reset their password

      // We need to generate a token for this user - expires in 1 hour = 60 minutes = 3600 seconds
      jwt.sign({ uid: matchingUid }, functions.config().jwt.secret, { expiresIn: 60 * 60 }, (errorCreatingToken, tokenToSend) => {

        if (errorCreatingToken) {
          console.log('Error creating user token:');
          console.log(errorCreatingToken);
          let objToReplyWith = {
            message: 'Error creating token for email. Please contact an adminstrator.'
          }
          res.json(objToReplyWith);
        } else {

          // Send token to user in email

          // Initialize the mailOptions variable
          const mailOptions = {
            from: gmailEmail,
            to: emailForUser,
          };
          // Building Email message.
          mailOptions.subject = 'LMS Password Reset';
          mailOptions.text = `
Dear ${req.body.userIdToFind.toUpperCase()},

The <system> at <company> has received a "Forgot Password" request for your account.
Please visit the following site to reset your password:
https://project.firebaseapp.com/home/reset-password-by-token/${tokenToSend}

If you have additional problems logging into LMS, please contact an adminstrator.

Sincerely,
<company>
          `;
          // Actually send the email, we need to reply with JSON
          mailTransport.sendMail(mailOptions).then( () => {
            // Successfully sent email
            let objToReplyWith = {
              message: 'An email has been sent to your email address containing a link to reset your password.'
            }
            res.json(objToReplyWith);
          }).catch( err => {
            // Failed to send email
            console.log('There was an error while sending the email:');
            console.log(err);
            let objToReplyWith = {
              message: 'Error sending password reset email. Please contact an adminstrator.'
            }
            res.json(objToReplyWith);
          });

        }

      })

    }

  }).catch( err => {
    console.log('Error finding all users in database:');
    console.log(err);
    res.send(false);
  })

});



// Called when the unauthenticated user tries to reset their password from the reset-password-by-token page
// User received an email with a link to the reset-password-by-token/TOKEN-HERE page, with a valid token
// We need to validate that token, and if valid - reset the password
exports.forgotPasswordReset = functions.https.onRequest( (req, res) => {

  // Look at the accessToken provided in the request, and have JWT verify whether it's valid or not
  jwt.verify(req.body.accessToken, functions.config().jwt.secret, (errorDecodingToken, decodedToken) => {

    if (errorDecodingToken) {
      console.error('Error while verifying JWT token:');
      console.log(error);
      res.send(false);
    }

    // Token was valid, pull the UID out of the token for the user making this request
    let requestorUid = decodedToken.uid;

    admin.auth().updateUser(requestorUid, {
      password: req.body.newPassword
    }).then( userRecord => {
      // Successfully updated password
      let objToReplyWith = {
        message: 'Successfully reset password'
      }
      res.json(objToReplyWith);
    }).catch( error => {
      console.log("Error updating password for user:");
      console.log(error)
      res.send(false);
    });

  });

});

2019 年 1 月

Admin SDK 现在有一些方法可以让您生成密码重置链接",将人们引导到内置的 Firebase 密码重置页面.这并不是 OP 正在寻找的解决方案,但已经很接近了.您仍然需要构建和发送电子邮件,如我的原始答案所示,但您不必做其他所有事情...即:生成 JWT,在您的应用程序中构建一个页面来处理 JWT,以及另一个后端函数来实际重置密码.

The Admin SDK now has some methods that allow you to generate a "password reset link" that will direct people to the built-in Firebase password reset page. This isn't exactly the solution OP was looking for, but it's close. You will still have to build and send the email, as my original answer shows, but you don't have to do everything else... i.e.: generate a JWT, build a page in your app to handle the JWT, and another backend function to actually reset the password.

查看电子邮件操作链接上的文档,特别是生成密码重置电子邮件链接"部分.

Check out the docs on the email action links, specifically the "Generate password reset email link" section.

// Admin SDK API to generate the password reset link.
const email = 'user@example.com';
admin.auth().generatePasswordResetLink(email, actionCodeSettings)
    .then((link) => {
        // Do stuff with link here
        // Construct password reset email template, embed the link and send
        // using custom SMTP server
    })
    .catch((error) => {
        // Some error occurred.
    });

完全披露 - 我实际上没有使用过任何这些功能,而且我有点担心相关页面大量引用移动应用程序 - 所以你可能必须通过它移动应用配置.

Full disclosure - I haven't actually used any of those functions, and I'm a little concerned that the page in question refers a lot to mobile apps - so you might have to pass it the mobile app config.

const actionCodeSettings = {
    // URL you want to redirect back to. The domain (www.example.com) for
    // this URL must be whitelisted in the Firebase Console.
    url: 'https://www.example.com/checkout?cartId=1234',
    // This must be true for email link sign-in.
    handleCodeInApp: true,
    iOS: {
        bundleId: 'com.example.ios'
    },
    android: {
        packageName: 'com.example.android',
        installApp: true,
        minimumVersion: '12'
    },
    // FDL custom domain.
    dynamicLinkDomain: 'coolapp.page.link'
};

另一方面,该页面还说这些功能提供了以下功能:

On the other hand, the page also says these features provide the ability to:

能够通过手机自定义链接的打开方式应用程序或浏览器,以及如何传递附加状态信息等.

Ability to customize how the link is to be opened, through a mobile app or a browser, and how to pass additional state information, etc.

这听起来很有希望,允许它在浏览器中打开......但是如果你正在为网络开发 - 并且在没有提供 iOS/Android 信息时功能会出错......那么恐怕你将不得不用老式的方法来创建你自己的实现......但我倾向于这个 .generatePasswordResetLink 现在应该可以工作了.

Which sounds promising, allowing it to open in the browser... but if you are developing for web - and the function errors out when not provided iOS/Android information... then I'm afraid you'll have to do it the old fashioned approach and create your own implementation... but I'm leaning towards this .generatePasswordResetLink should work now.

这篇关于Firebase:如何使用 NodeJs 发送密码重置电子邮件后端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆