Firebase:如何使用NodeJ发送密码重置电子邮件后端

时间:2018-07-13 12:55:43

标签: node.js firebase firebase-authentication google-cloud-functions

我试图隐含以下代码:https://firebase.google.com/docs/auth/web/manage-users#send_a_password_reset_email

string

但是我在firebase admin中找不到var auth = firebase.auth(); var emailAddress = "user@example.com"; auth.sendPasswordResetEmail(emailAddress).then(function() { // Email sent. }).catch(function(error) { // An error happened. }); 方法。

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

4 个答案:

答案 0 :(得分:3)

2018年7月原始答案:

sendPasswordResetEmail()方法是客户端auth模块中的一种方法,您是对的,Admin-SDK没有它-或任何类似的方法。大多数人从前端调用此功能...

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

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,以及另一个后端实际重置密码的功能。

查看email action links上的文档,特别是“ 生成密码重置电子邮件链接”部分。

// 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.
    });

全面披露-我实际上没有使用过任何这些功能,而且我有点担心所涉及的页面在很大程度上涉及移动应用程序-因此您可能必须通过它移动应用程序配置。

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'
};

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

  

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

这听起来很有希望,允许它在浏览器中打开...但是,如果您是为Web开发的,并且在未提供iOS / Android信息时出现了功能错误...那么,恐怕您必须采取老式的方法并创建自己的实现...但是我倾向于这种.generatePasswordResetLink现在应该可以使用。

答案 1 :(得分:0)

为什么不从您的前端发送它?

function resetPassword(emailAddress){
    firebase.auth().sendPasswordResetEmail(emailAddress).then(function() {
      console.log('email sent!');
    }).catch(function(error) {
      // An error happened.
    });
}

答案 2 :(得分:0)

public  void resetpasswoord()
{

    string emailaddress = resest_email.text;
    FirebaseAuth.DefaultInstance.SendPasswordResetEmailAsync(emailaddress).ContinueWith((task =>
    {

        if (task.IsCompleted)
        {
            Debug.Log("Email sent.");

        }
        if (task.IsFaulted)
        {
            Firebase.FirebaseException e =
           task.Exception.Flatten().InnerExceptions[0] as Firebase.FirebaseException;

            GetErrorMessage((AuthError)e.ErrorCode);
            errorpanal = true;
            return;
        }

    }));

}
  void GetErrorMessage(AuthError errorcode)
{
    string msg = "";
    msg = errorcode.ToString();

    print(msg);
    errorpanal = true;
    ErrorText.text = msg;
}

答案 3 :(得分:-2)

客户端库是一个npm包,与其他任何库一样。您可以从后端使用它:

const firebase = require('firebase');
const test_email = "test@test.com";
const config = {} // TODO: fill

const app = firebase.initializeApp(config);
app.auth().sendPasswordResetEmail(test_email).then(() => {
  console.log('email sent!');
}).catch(function(error) {
  // An error happened.
});