ตรวจสอบสิทธิ์ด้วย Firebase โดยใช้ลิงก์อีเมลใน JavaScript

คุณสามารถใช้การตรวจสอบสิทธิ์ Firebase เพื่อลงชื่อเข้าใช้ผู้ใช้โดยการส่งอีเมลที่มีลิงก์ให้ผู้ใช้คลิกเพื่อลงชื่อเข้าใช้ ในกระบวนการนี้ ระบบจะยืนยันอีเมลของผู้ใช้ด้วย

การลงชื่อเข้าใช้ด้วยอีเมลมีประโยชน์มากมาย ดังนี้

  • การลงชื่อสมัครใช้และการลงชื่อเข้าใช้ที่ง่ายดาย
  • ความเสี่ยงในการใช้รหัสผ่านซ้ำในแอปพลิเคชันต่างๆ ลดลง ซึ่งอาจทำให้รหัสผ่านที่เลือกมาอย่างดีมีความปลอดภัยน้อยลง
  • สามารถตรวจสอบสิทธิ์ผู้ใช้พร้อมกับยืนยันว่าผู้ใช้เป็นเจ้าของอีเมลที่ถูกต้อง
  • ผู้ใช้เพียงแค่ต้องมีบัญชีอีเมลที่เข้าถึงได้เพื่อลงชื่อเข้าใช้ ไม่จำเป็นต้องเป็นเจ้าของหมายเลขโทรศัพท์หรือบัญชีโซเชียลมีเดีย
  • ผู้ใช้สามารถลงชื่อเข้าใช้อย่างปลอดภัยโดยไม่ต้องระบุ (หรือจดจำ) รหัสผ่าน ซึ่งอาจเป็นเรื่องยุ่งยากในอุปกรณ์เคลื่อนที่
  • ผู้ใช้เดิมที่เคยลงชื่อเข้าใช้ด้วยตัวระบุอีเมล (รหัสผ่านหรือแบบรวมศูนย์) สามารถอัปเกรดให้ลงชื่อเข้าใช้ด้วยอีเมลเท่านั้นได้ ตัวอย่างเช่น ผู้ใช้ที่ลืมรหัสผ่านจะยังคงลงชื่อเข้าใช้ได้โดยไม่ต้องรีเซ็ตรหัสผ่าน

ก่อนเริ่มต้น

หากยังไม่ได้ทำ ให้คัดลอกข้อมูลโค้ดเริ่มต้นจาก Firebaseคอนโซลไปยังโปรเจ็กต์ตามที่อธิบายไว้ใน เพิ่ม Firebase ลงในโปรเจ็กต์ JavaScript

หากต้องการให้ผู้ใช้ลงชื่อเข้าใช้ด้วยลิงก์อีเมล คุณต้องเปิดใช้ผู้ให้บริการอีเมลและวิธีการลงชื่อเข้าใช้ด้วยลิงก์อีเมลสำหรับโปรเจ็กต์ Firebase ก่อน โดยทำดังนี้

  1. ในคอนโซล Firebase ให้ไปที่ความปลอดภัย > การตรวจสอบสิทธิ์

  2. ในแท็บวิธีการลงชื่อเข้าใช้ ให้เปิดใช้วิธีการลงชื่อเข้าใช้ด้วยอีเมล/รหัสผ่าน โปรดทราบว่าต้องเปิดใช้การลงชื่อเข้าใช้ด้วยอีเมล/รหัสผ่านก่อนจึงจะใช้การลงชื่อเข้าใช้ด้วยลิงก์อีเมลได้

  3. ในส่วนเดียวกัน ให้เปิดใช้ผู้ให้บริการการลงชื่อเข้าใช้ด้วยลิงก์อีเมล (ลงชื่อเข้าใช้แบบไม่ต้องใช้รหัสผ่าน)

  4. คลิกบันทึก

หากต้องการเริ่มขั้นตอนการตรวจสอบสิทธิ์ ให้แสดงอินเทอร์เฟซที่แจ้งให้ผู้ใช้ระบุอีเมล แล้วเรียก sendSignInLinkToEmail เพื่อขอให้ Firebase ส่งลิงก์การตรวจสอบสิทธิ์ไปยังอีเมลของผู้ใช้

  1. สร้างออบเจ็กต์ ActionCodeSettings ซึ่งจะให้คำแนะนำแก่ Firebase เกี่ยวกับวิธีสร้างลิงก์อีเมล ตั้งค่าฟิลด์ต่อไปนี้

    • url: Deep Link ที่จะฝังและสถานะเพิ่มเติมที่จะส่งต่อ เพิ่มโดเมนลงในรายการโดเมนที่ได้รับอนุญาต หากยังไม่ได้เพิ่ม โดยทำดังนี้

      1. ในคอนโซลFirebase ให้ไปที่แท็บ ความปลอดภัย > การตรวจสอบสิทธิ์ > การตั้งค่า

      2. ในส่วนโดเมนที่ได้รับอนุญาต ให้คลิกเพิ่มโดเมน แล้วเพิ่ม โดเมน

    • android และ ios: ช่วย Firebase Authentication ในการพิจารณาว่าจะสร้างลิงก์สำหรับเว็บเท่านั้นหรือลิงก์สำหรับมือถือซึ่งจะเปิดในอุปกรณ์ Android หรือ Apple
    • handleCodeInApp: ตั้งค่าเป็น "จริง" การดำเนินการลงชื่อเข้าใช้ต้องดำเนินการให้เสร็จสมบูรณ์ในแอปเสมอ ซึ่งแตกต่างจากการดำเนินการทางอีเมลอื่นๆ นอกแอป (การรีเซ็ตรหัสผ่านและการยืนยันอีเมล) เนื่องจากในตอนท้ายของขั้นตอน ผู้ใช้จะต้องลงชื่อเข้าใช้และสถานะการตรวจสอบสิทธิ์จะยังคงอยู่ในแอป
    • linkDomain: เมื่อมีการกำหนดโดเมนลิงก์ที่กำหนดเองสำหรับโปรเจ็กต์ ให้ระบุโดเมนที่จะใช้เมื่อแอปบนอุปกรณ์เคลื่อนที่ที่ระบุจะเปิดลิงก์ มิเช่นนั้น ระบบจะเลือกโดเมนเริ่มต้นโดยอัตโนมัติ (เช่น PROJECT_ID.firebaseapp.com)Hosting
    • dynamicLinkDomain: เลิกใช้งานแล้ว อย่าระบุพารามิเตอร์นี้

      Web

      const actionCodeSettings = {
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be in the authorized domains list in the Firebase Console.
        url: 'https://www.example.com/finishSignUp?cartId=1234',
        // This must be true.
        handleCodeInApp: true,
        iOS: {
          bundleId: 'com.example.ios'
        },
        android: {
          packageName: 'com.example.android',
          installApp: true,
          minimumVersion: '12'
        },
        // The domain must be configured in Firebase Hosting and owned by the project.
        linkDomain: 'custom-domain.com'
      };

      Web

      var actionCodeSettings = {
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be in the authorized domains list in the Firebase Console.
        url: 'https://www.example.com/finishSignUp?cartId=1234',
        // This must be true.
        handleCodeInApp: true,
        iOS: {
          bundleId: 'com.example.ios'
        },
        android: {
          packageName: 'com.example.android',
          installApp: true,
          minimumVersion: '12'
        },
        dynamicLinkDomain: 'example.page.link'
      };

    ดูข้อมูลเพิ่มเติมเกี่ยวกับ ActionCodeSettings ได้ที่ส่วน การส่งสถานะในการดำเนินการทางอีเมล

  2. ขออีเมลจากผู้ใช้

  3. ส่งลิงก์การตรวจสอบสิทธิ์ไปยังอีเมลของผู้ใช้ และบันทึกอีเมลของผู้ใช้ไว้ในกรณีที่ผู้ใช้ลงชื่อเข้าใช้ด้วยอีเมลในอุปกรณ์เครื่องเดียวกัน

    Web

    import { getAuth, sendSignInLinkToEmail } from "firebase/auth";
    
    const auth = getAuth();
    sendSignInLinkToEmail(auth, email, actionCodeSettings)
      .then(() => {
        // The link was successfully sent. Inform the user.
        // Save the email locally so you don't need to ask the user for it again
        // if they open the link on the same device.
        window.localStorage.setItem('emailForSignIn', email);
        // ...
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
        // ...
      });

    Web

    firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings)
      .then(() => {
        // The link was successfully sent. Inform the user.
        // Save the email locally so you don't need to ask the user for it again
        // if they open the link on the same device.
        window.localStorage.setItem('emailForSignIn', email);
        // ...
      })
      .catch((error) => {
        var errorCode = error.code;
        var errorMessage = error.message;
        // ...
      });

ข้อกังวลด้านความปลอดภัย

เพื่อป้องกันไม่ให้มีการใช้ลิงก์การลงชื่อเข้าใช้เพื่อลงชื่อเข้าใช้เป็นผู้ใช้ที่ไม่ต้องการหรือในอุปกรณ์ที่ไม่ต้องการ การตรวจสอบสิทธิ์ Firebase กำหนดให้ระบุอีเมลของผู้ใช้เมื่อดำเนินการตามขั้นตอนการลงชื่อเข้าใช้ให้เสร็จสมบูรณ์ อีเมลนี้ต้องตรงกับอีเมลที่ส่งลิงก์การลงชื่อเข้าใช้ไปให้ในตอนแรกเพื่อให้การลงชื่อเข้าใช้สำเร็จ

คุณสามารถปรับปรุงขั้นตอนการทำงานนี้ให้ง่ายขึ้นสำหรับผู้ใช้ที่เปิดลิงก์การลงชื่อเข้าใช้ในอุปกรณ์เครื่องเดียวกับที่ขอลิงก์ โดยจัดเก็บอีเมลของผู้ใช้ไว้ในเครื่อง เช่น ใช้ localStorage หรือคุกกี้ เมื่อคุณส่งอีเมลการลงชื่อเข้าใช้ จากนั้นใช้ที่อยู่นี้เพื่อดำเนินการตามขั้นตอนให้เสร็จสมบูรณ์ อย่าส่งอีเมลของผู้ใช้ในพารามิเตอร์ URL การเปลี่ยนเส้นทางและนำอีเมลนั้นกลับมาใช้ซ้ำ เนื่องจากอาจทำให้เกิดการแทรกเซสชันได้

หลังจากลงชื่อเข้าใช้เสร็จสมบูรณ์ ระบบจะนำกลไกการลงชื่อเข้าใช้ที่ยังไม่ได้รับการยืนยันก่อนหน้านี้ออกจากผู้ใช้ และเซสชันที่มีอยู่จะใช้งานไม่ได้ ตัวอย่างเช่น หากมีคนสร้างบัญชีที่ยังไม่ได้รับการยืนยันด้วยอีเมลและรหัสผ่านเดียวกันก่อนหน้านี้ ระบบจะนำรหัสผ่านของผู้ใช้ออกเพื่อป้องกันไม่ให้ผู้แอบอ้างที่อ้างสิทธิ์เป็นเจ้าของและสร้างบัญชีที่ยังไม่ได้รับการยืนยันนั้นลงชื่อเข้าใช้อีกครั้งด้วยอีเมลและรหัสผ่านที่ยังไม่ได้รับการยืนยัน

นอกจากนี้ โปรดตรวจสอบว่าคุณใช้ URL HTTPS ในการใช้งานจริงเพื่อป้องกันไม่ให้เซิร์ฟเวอร์ตัวกลางสกัดกั้นลิงก์ของคุณ

การลงชื่อเข้าใช้ในหน้าเว็บให้เสร็จสมบูรณ์

รูปแบบของ Deep Link ของลิงก์อีเมลจะเหมือนกับ รูปแบบที่ใช้สำหรับการดำเนินการทางอีเมลนอกแอป (การยืนยันอีเมล การรีเซ็ตรหัสผ่าน และการเพิกถอนการเปลี่ยนแปลงอีเมล) การตรวจสอบสิทธิ์ Firebase ช่วยให้การตรวจสอบนี้ง่ายขึ้นโดยมี API isSignInWithEmailLink เพื่อตรวจสอบว่าลิงก์เป็นลิงก์การลงชื่อเข้าใช้ด้วยอีเมลหรือไม่

หากต้องการลงชื่อเข้าใช้ในหน้า Landing Page ให้เรียก signInWithEmailLink ด้วยอีเมลของผู้ใช้และลิงก์อีเมลจริงที่มีรหัสแบบใช้ครั้งเดียว

Web

import { getAuth, isSignInWithEmailLink, signInWithEmailLink } from "firebase/auth";

// Confirm the link is a sign-in with email link.
const auth = getAuth();
if (isSignInWithEmailLink(auth, window.location.href)) {
  // Additional state parameters can also be passed via URL.
  // This can be used to continue the user's intended action before triggering
  // the sign-in operation.
  // Get the email if available. This should be available if the user completes
  // the flow on the same device where they started it.
  let email = window.localStorage.getItem('emailForSignIn');
  if (!email) {
    // User opened the link on a different device. To prevent session fixation
    // attacks, ask the user to provide the associated email again. For example:
    email = window.prompt('Please provide your email for confirmation');
  }
  // The client SDK will parse the code from the link for you.
  signInWithEmailLink(auth, email, window.location.href)
    .then((result) => {
      // Clear email from storage.
      window.localStorage.removeItem('emailForSignIn');
      // You can access the new user by importing getAdditionalUserInfo
      // and calling it with result:
      // getAdditionalUserInfo(result)
      // You can access the user's profile via:
      // getAdditionalUserInfo(result)?.profile
      // You can check if the user is new or existing:
      // getAdditionalUserInfo(result)?.isNewUser
    })
    .catch((error) => {
      // Some error occurred, you can inspect the code: error.code
      // Common errors could be invalid email and invalid or expired OTPs.
    });
}

Web

// Confirm the link is a sign-in with email link.
if (firebase.auth().isSignInWithEmailLink(window.location.href)) {
  // Additional state parameters can also be passed via URL.
  // This can be used to continue the user's intended action before triggering
  // the sign-in operation.
  // Get the email if available. This should be available if the user completes
  // the flow on the same device where they started it.
  var email = window.localStorage.getItem('emailForSignIn');
  if (!email) {
    // User opened the link on a different device. To prevent session fixation
    // attacks, ask the user to provide the associated email again. For example:
    email = window.prompt('Please provide your email for confirmation');
  }
  // The client SDK will parse the code from the link for you.
  firebase.auth().signInWithEmailLink(email, window.location.href)
    .then((result) => {
      // Clear email from storage.
      window.localStorage.removeItem('emailForSignIn');
      // You can access the new user via result.user
      // Additional user info profile not available via:
      // result.additionalUserInfo.profile == null
      // You can check if the user is new or existing:
      // result.additionalUserInfo.isNewUser
    })
    .catch((error) => {
      // Some error occurred, you can inspect the code: error.code
      // Common errors could be invalid email and invalid or expired OTPs.
    });
}

การลงชื่อเข้าใช้ในแอปบนอุปกรณ์เคลื่อนที่ให้เสร็จสมบูรณ์

Firebase Authentication ใช้ Firebase Hosting เพื่อส่งลิงก์อีเมลไปยัง อุปกรณ์เคลื่อนที่ หากต้องการลงชื่อเข้าใช้ให้เสร็จสมบูรณ์ผ่านแอปพลิเคชันบนอุปกรณ์เคลื่อนที่ คุณต้องกำหนดค่าแอปพลิเคชันให้ตรวจหาลิงก์แอปพลิเคชันขาเข้า แยกวิเคราะห์ Deep Link ที่เกี่ยวข้อง แล้วลงชื่อเข้าใช้ให้เสร็จสมบูรณ์ตามที่ทำผ่านขั้นตอนการทำงานของเว็บ

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีจัดการการลงชื่อเข้าใช้ด้วยลิงก์อีเมลในแอปพลิเคชัน Android ได้ที่คู่มือ Android

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีจัดการการลงชื่อเข้าใช้ด้วยลิงก์อีเมลในแอปพลิเคชัน Apple ได้ที่คู่มือแพลตฟอร์ม Apple

นอกจากนี้ คุณยังลิงก์วิธีการตรวจสอบสิทธิ์นี้กับผู้ใช้ที่มีอยู่ได้ด้วย ตัวอย่างเช่น ผู้ใช้ที่เคยตรวจสอบสิทธิ์กับผู้ให้บริการรายอื่น เช่น หมายเลขโทรศัพท์ สามารถเพิ่มวิธีการลงชื่อเข้าใช้นี้ลงในบัญชีที่มีอยู่ได้

ความแตกต่างจะอยู่ที่ครึ่งหลังของการดำเนินการ ดังนี้

Web

import { getAuth, linkWithCredential, EmailAuthProvider } from "firebase/auth";

// Construct the email link credential from the current URL.
const credential = EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Link the credential to the current user.
const auth = getAuth();
linkWithCredential(auth.currentUser, credential)
  .then((usercred) => {
    // The provider is now successfully linked.
    // The phone user can now sign in with their phone number or email.
  })
  .catch((error) => {
    // Some error occurred.
  });

Web

// Construct the email link credential from the current URL.
var credential = firebase.auth.EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Link the credential to the current user.
firebase.auth().currentUser.linkWithCredential(credential)
  .then((usercred) => {
    // The provider is now successfully linked.
    // The phone user can now sign in with their phone number or email.
  })
  .catch((error) => {
    // Some error occurred.
  });

นอกจากนี้ คุณยังใช้วิธีนี้เพื่อตรวจสอบสิทธิ์ผู้ใช้ลิงก์อีเมลอีกครั้งก่อนที่จะดำเนินการที่ละเอียดอ่อนได้ด้วย

Web

import { getAuth, reauthenticateWithCredential, EmailAuthProvider } from "firebase/auth";

// Construct the email link credential from the current URL.
const credential = EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Re-authenticate the user with this credential.
const auth = getAuth();
reauthenticateWithCredential(auth.currentUser, credential)
  .then((usercred) => {
    // The user is now successfully re-authenticated and can execute sensitive
    // operations.
  })
  .catch((error) => {
    // Some error occurred.
  });

Web

// Construct the email link credential from the current URL.
var credential = firebase.auth.EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Re-authenticate the user with this credential.
firebase.auth().currentUser.reauthenticateWithCredential(credential)
  .then((usercred) => {
    // The user is now successfully re-authenticated and can execute sensitive
    // operations.
  })
  .catch((error) => {
    // Some error occurred.
  });

อย่างไรก็ตาม ขั้นตอนการทำงานนี้อาจไม่เสร็จสมบูรณ์เนื่องจากอาจสิ้นสุดในอุปกรณ์เครื่องอื่นที่ผู้ใช้เดิมไม่ได้เข้าสู่ระบบ ในกรณีดังกล่าว คุณสามารถแสดงข้อผิดพลาดให้ผู้ใช้บังคับให้เปิดลิงก์ในอุปกรณ์เครื่องเดียวกัน คุณสามารถส่งสถานะบางอย่างในลิงก์เพื่อระบุข้อมูลเกี่ยวกับประเภทการดำเนินการและ UID ของผู้ใช้

หากคุณสร้างโปรเจ็กต์ตั้งแต่วันที่ 15 กันยายน 2023 เป็นต้นไป ระบบจะเปิดใช้การป้องกันการแจกแจงอีเมลโดยค่าเริ่มต้น ฟีเจอร์นี้ช่วยปรับปรุงความปลอดภัยของบัญชีผู้ใช้ในโปรเจ็กต์ แต่จะปิดใช้เมธอด fetchSignInMethodsForEmail() ซึ่งเราเคยแนะนำให้ใช้เพื่อดำเนินการตามขั้นตอนการทำงานแบบระบุตัวระบุเป็นอันดับแรก

แม้ว่าคุณจะปิดใช้การป้องกันการแจกแจงอีเมลสำหรับโปรเจ็กต์ได้ แต่เราไม่แนะนำให้ทำเช่นนั้น

ดูรายละเอียดเพิ่มเติมได้ในเอกสารประกอบเกี่ยวกับการป้องกันการแจกแจงอีเมล

เทมเพลตอีเมลเริ่มต้นสำหรับการลงชื่อเข้าใช้ด้วยลิงก์

เทมเพลตอีเมลเริ่มต้นจะมีข้อมูลประทับเวลาในเรื่องและเนื้อหาของอีเมล เพื่อไม่ให้ระบบยุบอีเมลที่ตามมาเป็นชุดข้อความเดียวและซ่อนลิงก์

เทมเพลตนี้ใช้ได้กับภาษาต่อไปนี้

รหัส ภาษา
ar อาหรับ
zh-CN จีน (ตัวย่อ)
zh-TW จีน (ดั้งเดิม)
nl ดัตช์
en อังกฤษ
en-GB อังกฤษ (สหราชอาณาจักร)
fr ฝรั่งเศส
de เยอรมัน
id อินโดนีเซีย
it อิตาลี
ja ญี่ปุ่น
ko เกาหลี
pl โปแลนด์
pt-BR โปรตุเกส (บราซิล)
pt-PT โปรตุเกส (โปรตุเกส)
ru รัสเซีย
es สเปน
es-419 สเปน (ละตินอเมริกา)
th ไทย

ขั้นตอนถัดไป

หลังจากที่ผู้ใช้ลงชื่อเข้าใช้เป็นครั้งแรก ระบบจะสร้างบัญชีผู้ใช้ใหม่และลิงก์กับข้อมูลเข้าสู่ระบบ นั่นคือ ชื่อผู้ใช้และรหัสผ่าน หมายเลขโทรศัพท์ หรือข้อมูลผู้ให้บริการการตรวจสอบสิทธิ์ที่ผู้ใช้ใช้ลงชื่อเข้าใช้ ระบบจะจัดเก็บบัญชีใหม่นี้เป็นส่วนหนึ่งของโปรเจ็กต์ Firebase และใช้เพื่อระบุผู้ใช้ในทุกแอปของโปรเจ็กต์ได้ ไม่ว่าผู้ใช้จะลงชื่อเข้าใช้ด้วยวิธีใดก็ตาม

  • ในแอป วิธีที่แนะนำในการทราบสถานะการตรวจสอบสิทธิ์ของผู้ใช้คือการตั้งค่า Observer ในออบเจ็กต์ Auth จากนั้นคุณจะได้รับข้อมูลโปรไฟล์พื้นฐานของผู้ใช้จากออบเจ็กต์ User ดูหัวข้อ จัดการผู้ใช้

  • ใน Firebase Realtime Database และ Cloud Storage กฎความปลอดภัย คุณสามารถ รับรหัสผู้ใช้ที่ไม่ซ้ำกันของผู้ใช้ที่ลงชื่อเข้าใช้จากตัวแปร auth และใช้รหัสนี้เพื่อควบคุมข้อมูลที่ผู้ใช้เข้าถึงได้

คุณสามารถอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้แอปโดยใช้ผู้ให้บริการการตรวจสอบสิทธิ์หลายรายได้โดยการลิงก์ข้อมูลเข้าสู่ระบบของผู้ให้บริการการตรวจสอบสิทธิ์กับบัญชีผู้ใช้ที่มีอยู่

หากต้องการให้ผู้ใช้ออกจากระบบ ให้เรียก signOut

Web

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});