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

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

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

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

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

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

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

  1. ในคอนโซล Firebase ให้เปิดส่วนการตรวจสอบสิทธิ์
  2. ในแท็บวิธีการลงชื่อเข้าใช้ ให้เปิดใช้ผู้ให้บริการอีเมล/รหัสผ่าน โปรดทราบว่าต้องเปิดใช้การลงชื่อเข้าใช้ด้วยอีเมล/รหัสผ่านเพื่อใช้การลงชื่อเข้าใช้ลิงก์อีเมล
  3. ในส่วนเดียวกัน ให้เปิดใช้วิธีการลงชื่อเข้าใช้ลิงก์อีเมล (การลงชื่อเข้าใช้แบบไม่ต้องใช้รหัสผ่าน)
  4. คลิกบันทึก

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

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

    • url: Deep Link ที่จะฝังและสถานะเพิ่มเติมที่จะส่งต่อ คุณต้องเพิ่มโดเมนของลิงก์ในรายการโดเมนที่ได้รับอนุญาตในคอนโซล Firebase ซึ่งดูได้โดยไปที่แท็บวิธีการลงชื่อเข้าใช้ (การตรวจสอบสิทธิ์ -> การตั้งค่า)
    • android และ ios: แอปที่จะใช้เมื่อเปิดลิงก์ลงชื่อเข้าใช้ในอุปกรณ์ Android หรือ Apple ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีกำหนดค่าลิงก์แบบไดนามิกของ Firebase เพื่อเปิดลิงก์การดำเนินการกับอีเมลผ่านแอปบนอุปกรณ์เคลื่อนที่
    • handleCodeInApp: ตั้งค่าเป็น "จริง" โดยจะต้องลงชื่อเข้าใช้ในแอปให้เสร็จสมบูรณ์เสมอ ซึ่งต่างจากการดำเนินการอื่นๆ เกี่ยวกับอีเมลนอกกลุ่ม (การรีเซ็ตรหัสผ่านและการยืนยันอีเมล) ทั้งนี้เพราะในตอนท้ายของขั้นตอนนี้ ผู้ใช้ต้องลงชื่อเข้าใช้และสถานะการตรวจสอบสิทธิ์ยังคงอยู่ภายในแอป
    • dynamicLinkDomain: เมื่อมีการกำหนดโดเมนลิงก์แบบไดนามิกที่กำหนดเองหลายโดเมนสำหรับโปรเจ็กต์ ให้ระบุโดเมนที่จะใช้เมื่อมีการเปิดลิงก์ผ่านแอปบนอุปกรณ์เคลื่อนที่ที่ระบุ (เช่น example.page.link) ไม่เช่นนั้นระบบจะเลือกโดเมนแรกโดยอัตโนมัติ

      Web Modular API

      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'
        },
        dynamicLinkDomain: 'example.page.link'
      };

      API ที่ใช้เนมสเปซในเว็บ

      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 ได้ที่ส่วน Passing State in Email Actions

  2. ขออีเมลของผู้ใช้

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

    Web Modular API

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

    API ที่ใช้เนมสเปซในเว็บ

    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 Auth กำหนดให้คุณต้องระบุอีเมลของผู้ใช้เมื่อเสร็จสิ้นขั้นตอนการลงชื่อเข้าใช้ เพื่อให้ลงชื่อเข้าใช้สำเร็จ อีเมลนี้ต้องตรงกับอีเมลที่ส่งลิงก์ลงชื่อเข้าใช้ให้ในตอนแรก

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

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

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

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

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

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

Web Modular API

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

API ที่ใช้เนมสเปซในเว็บ

// 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 ใช้ลิงก์แบบไดนามิกของ Firebase เพื่อส่งลิงก์อีเมลไปยังอุปกรณ์เคลื่อนที่ เพื่อให้ลงชื่อเข้าใช้ผ่านแอปพลิเคชันบนอุปกรณ์เคลื่อนที่ได้ จะต้องมีการกำหนดค่าแอปพลิเคชันให้ตรวจหาลิงก์แอปพลิเคชันขาเข้า แยกวิเคราะห์ Deep Link เบื้องหลัง แล้วลงชื่อเข้าใช้ให้เสร็จสมบูรณ์ตามที่ดำเนินการผ่านขั้นตอนบนเว็บ

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

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

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

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

Web Modular API

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

API ที่ใช้เนมสเปซในเว็บ

// 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 Modular API

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

API ที่ใช้เนมสเปซในเว็บ

// 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 ญี่ปุ่น
โค เกาหลี
pl โปแลนด์
PT-BR โปรตุเกส (บราซิล)
แต้ม โปรตุเกส (โปรตุเกส)
รู รัสเซีย
สเปน สเปน
ES_419 สเปน (ลาตินอเมริกา)
th ไทย

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

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

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

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

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

หากต้องการนำผู้ใช้ออกจากระบบ โปรดโทรหา signOut:

Web Modular API

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

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

API ที่ใช้เนมสเปซในเว็บ

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