建立自訂電子郵件動作處理常式

有些使用者管理動作 (例如更新使用者的電子郵件地址及重設使用者的密碼) 會導致電子郵件傳送給使用者。這些電子郵件內含連結,讓收件者可以開啟或取消管理使用者操作。根據預設,使用者管理的電子郵件會連結至預設動作處理常式,也就是託管在專案 Firebase 託管網域中某個網址的網頁。

您可改為建立及代管自訂電子郵件動作處理常式,以執行自訂處理,並將電子郵件動作處理常式與網站整合。

下列使用者管理動作會要求使用者使用電子郵件動作處理常式完成此動作:

  • 重設密碼
  • 撤銷電子郵件地址變更:使用者變更帳戶的主要電子郵件地址時,Firebase 會傳送電子郵件到他們舊的電子郵件地址,讓他們復原變更。
  • 驗證電子郵件地址

如要自訂 Firebase 專案的電子郵件動作處理常式,您必須建立並託管一個使用 Firebase JavaScript SDK 的網頁,以驗證要求的有效性並完成要求。然後,您必須自訂 Firebase 專案的電子郵件範本,以連結至自訂動作處理常式。

建立電子郵件動作處理常式頁面

  1. Firebase 產生使用者管理電子郵件時,會將多個查詢參數新增至您的動作處理常式網址。例如:

    https://example.com/usermgmt?mode=resetPassword&oobCode=ABC123&apiKey=AIzaSy...&lang=fr

    這些參數會指定使用者要完成的使用者管理工作。您的電子郵件動作處理常式頁面必須處理下列查詢參數:

    參數
    模式

    要完成的使用者管理動作。可以是下列其中一個值:

    • resetPassword
    • recoverEmail
    • verifyEmail
    oobCode 一次性代碼,用於識別及驗證要求
    API 金鑰 Firebase 專案的 API 金鑰,為了方便起見
    繼續網址 此為選用網址,可讓您透過網址將狀態傳回應用程式。這與重設密碼和電子郵件驗證模式有關。傳送密碼重設電子郵件或驗證電子郵件時,您必須使用繼續網址指定 ActionCodeSettings 物件,才能使用這個繼續網址。如此一來,使用者在執行電子郵件動作後,就可以從上次中斷的地方繼續。
    語言

    這是選填的 BCP47 語言標記,代表使用者的語言代碼 (例如 fr)。您可以使用這個值,向使用者提供本地化的電子郵件動作處理常式頁面。

    您可以透過 Firebase 控制台或在觸發電子郵件動作前呼叫對應的用戶端 API,以動態方式設定本地化作業。例如,使用 JavaScript:firebase.auth().languageCode = 'fr';

    為提供一致的使用者體驗,請確保電子郵件動作處理常式本地化與電子郵件範本的本地化相符。

    以下範例說明如何在瀏覽器式處理常式中處理查詢參數。(您也可以使用類似的邏輯,將處理常式實作為 Node.js 應用程式)。

    網頁模組 API

    import { initializeApp } from "firebase/app";
    import { getAuth } from "firebase/auth";
    
    document.addEventListener('DOMContentLoaded', () => {
      // TODO: Implement getParameterByName()
    
      // Get the action to complete.
      const mode = getParameterByName('mode');
      // Get the one-time code from the query parameter.
      const actionCode = getParameterByName('oobCode');
      // (Optional) Get the continue URL from the query parameter if available.
      const continueUrl = getParameterByName('continueUrl');
      // (Optional) Get the language code if available.
      const lang = getParameterByName('lang') || 'en';
    
      // Configure the Firebase SDK.
      // This is the minimum configuration required for the API to be used.
      const config = {
        'apiKey': "YOUR_API_KEY" // Copy this key from the web initialization
                                 // snippet found in the Firebase console.
      };
      const app = initializeApp(config);
      const auth = getAuth(app);
    
      // Handle the user management action.
      switch (mode) {
        case 'resetPassword':
          // Display reset password handler and UI.
          handleResetPassword(auth, actionCode, continueUrl, lang);
          break;
        case 'recoverEmail':
          // Display email recovery handler and UI.
          handleRecoverEmail(auth, actionCode, lang);
          break;
        case 'verifyEmail':
          // Display email verification handler and UI.
          handleVerifyEmail(auth, actionCode, continueUrl, lang);
          break;
        default:
          // Error: invalid mode.
      }
    }, false);

    網路命名空間 API

    document.addEventListener('DOMContentLoaded', () => {
      // TODO: Implement getParameterByName()
    
      // Get the action to complete.
      var mode = getParameterByName('mode');
      // Get the one-time code from the query parameter.
      var actionCode = getParameterByName('oobCode');
      // (Optional) Get the continue URL from the query parameter if available.
      var continueUrl = getParameterByName('continueUrl');
      // (Optional) Get the language code if available.
      var lang = getParameterByName('lang') || 'en';
    
      // Configure the Firebase SDK.
      // This is the minimum configuration required for the API to be used.
      var config = {
        'apiKey': "YOU_API_KEY" // Copy this key from the web initialization
                                // snippet found in the Firebase console.
      };
      var app = firebase.initializeApp(config);
      var auth = app.auth();
    
      // Handle the user management action.
      switch (mode) {
        case 'resetPassword':
          // Display reset password handler and UI.
          handleResetPassword(auth, actionCode, continueUrl, lang);
          break;
        case 'recoverEmail':
          // Display email recovery handler and UI.
          handleRecoverEmail(auth, actionCode, lang);
          break;
        case 'verifyEmail':
          // Display email verification handler and UI.
          handleVerifyEmail(auth, actionCode, continueUrl, lang);
          break;
        default:
          // Error: invalid mode.
      }
    }, false);
  2. 處理密碼重設要求時,請先使用 verifyPasswordResetCode 驗證動作程式碼,接著向使用者取得新密碼,並傳遞至 confirmPasswordReset。例如:

    網頁模組 API

    import { verifyPasswordResetCode, confirmPasswordReset } from "firebase/auth";
    
    function handleResetPassword(auth, actionCode, continueUrl, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
    
      // Verify the password reset code is valid.
      verifyPasswordResetCode(auth, actionCode).then((email) => {
        const accountEmail = email;
    
        // TODO: Show the reset screen with the user's email and ask the user for
        // the new password.
        const newPassword = "...";
    
        // Save the new password.
        confirmPasswordReset(auth, actionCode, newPassword).then((resp) => {
          // Password reset has been confirmed and new password updated.
    
          // TODO: Display a link back to the app, or sign-in the user directly
          // if the page belongs to the same domain as the app:
          // auth.signInWithEmailAndPassword(accountEmail, newPassword);
    
          // TODO: If a continue URL is available, display a button which on
          // click redirects the user back to the app via continueUrl with
          // additional state determined from that URL's parameters.
        }).catch((error) => {
          // Error occurred during confirmation. The code might have expired or the
          // password is too weak.
        });
      }).catch((error) => {
        // Invalid or expired action code. Ask user to try to reset the password
        // again.
      });
    }

    網路命名空間 API

    function handleResetPassword(auth, actionCode, continueUrl, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
    
      // Verify the password reset code is valid.
      auth.verifyPasswordResetCode(actionCode).then((email) => {
        var accountEmail = email;
    
        // TODO: Show the reset screen with the user's email and ask the user for
        // the new password.
        var newPassword = "...";
    
        // Save the new password.
        auth.confirmPasswordReset(actionCode, newPassword).then((resp) => {
          // Password reset has been confirmed and new password updated.
    
          // TODO: Display a link back to the app, or sign-in the user directly
          // if the page belongs to the same domain as the app:
          // auth.signInWithEmailAndPassword(accountEmail, newPassword);
    
          // TODO: If a continue URL is available, display a button which on
          // click redirects the user back to the app via continueUrl with
          // additional state determined from that URL's parameters.
        }).catch((error) => {
          // Error occurred during confirmation. The code might have expired or the
          // password is too weak.
        });
      }).catch((error) => {
        // Invalid or expired action code. Ask user to try to reset the password
        // again.
      });
    }
  3. 處理電子郵件地址變更撤銷作業的方法是先使用 checkActionCode 驗證動作程式碼,然後使用 applyActionCode 還原使用者的電子郵件地址。例如:

    網頁模組 API

    import { checkActionCode, applyActionCode, sendPasswordResetEmail } from "firebase/auth";
    
    function handleRecoverEmail(auth, actionCode, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
      let restoredEmail = null;
      // Confirm the action code is valid.
      checkActionCode(auth, actionCode).then((info) => {
        // Get the restored email address.
        restoredEmail = info['data']['email'];
    
        // Revert to the old email.
        return applyActionCode(auth, actionCode);
      }).then(() => {
        // Account email reverted to restoredEmail
    
        // TODO: Display a confirmation message to the user.
    
        // You might also want to give the user the option to reset their password
        // in case the account was compromised:
        sendPasswordResetEmail(auth, restoredEmail).then(() => {
          // Password reset confirmation sent. Ask user to check their email.
        }).catch((error) => {
          // Error encountered while sending password reset code.
        });
      }).catch((error) => {
        // Invalid code.
      });
    }

    網路命名空間 API

    function handleRecoverEmail(auth, actionCode, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
      var restoredEmail = null;
      // Confirm the action code is valid.
      auth.checkActionCode(actionCode).then((info) => {
        // Get the restored email address.
        restoredEmail = info['data']['email'];
    
        // Revert to the old email.
        return auth.applyActionCode(actionCode);
      }).then(() => {
        // Account email reverted to restoredEmail
    
        // TODO: Display a confirmation message to the user.
    
        // You might also want to give the user the option to reset their password
        // in case the account was compromised:
        auth.sendPasswordResetEmail(restoredEmail).then(() => {
          // Password reset confirmation sent. Ask user to check their email.
        }).catch((error) => {
          // Error encountered while sending password reset code.
        });
      }).catch((error) => {
        // Invalid code.
      });
    }
  4. 呼叫 applyActionCode 來處理電子郵件地址驗證事宜。例如:

    網頁模組 API

    function handleVerifyEmail(auth, actionCode, continueUrl, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
      // Try to apply the email verification code.
      applyActionCode(auth, actionCode).then((resp) => {
        // Email address has been verified.
    
        // TODO: Display a confirmation message to the user.
        // You could also provide the user with a link back to the app.
    
        // TODO: If a continue URL is available, display a button which on
        // click redirects the user back to the app via continueUrl with
        // additional state determined from that URL's parameters.
      }).catch((error) => {
        // Code is invalid or expired. Ask the user to verify their email address
        // again.
      });
    }

    網路命名空間 API

    function handleVerifyEmail(auth, actionCode, continueUrl, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
      // Try to apply the email verification code.
      auth.applyActionCode(actionCode).then((resp) => {
        // Email address has been verified.
    
        // TODO: Display a confirmation message to the user.
        // You could also provide the user with a link back to the app.
    
        // TODO: If a continue URL is available, display a button which on
        // click redirects the user back to the app via continueUrl with
        // additional state determined from that URL's parameters.
      }).catch((error) => {
        // Code is invalid or expired. Ask the user to verify their email address
        // again.
      });
    }
  5. 將網頁託管於某個位置,例如使用 Firebase 代管

接下來,您必須設定 Firebase 專案,使其在使用者管理電子郵件中,連結至您的自訂電子郵件動作處理常式。

如要將 Firebase 專案設為使用自訂電子郵件動作處理常式,請按照下列步驟操作:

  1. Firebase 控制台開啟專案。
  2. 前往「驗證」部分的「電子郵件範本」頁面。
  3. 在任何「Email Types」(電子郵件類型) 項目中,按一下鉛筆圖示來編輯電子郵件範本。
  4. 按一下「customize action URL」,並指定自訂電子郵件動作處理常式的網址。

儲存網址後,所有 Firebase 專案的電子郵件範本都會使用這個網址。