Catch up on highlights from Firebase at Google I/O 2023. Learn more

ขยายการตรวจสอบสิทธิ์ Firebase ด้วยการบล็อกฟังก์ชั่นคลาวด์


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

ก่อนที่คุณจะเริ่มต้น

หากต้องการใช้ฟังก์ชันการบล็อก คุณต้องอัปเกรดโปรเจ็กต์ Firebase เป็น Firebase Authentication ด้วย Identity Platform หากคุณยังไม่ได้อัปเกรด ให้ดำเนินการก่อน

ทำความเข้าใจเกี่ยวกับฟังก์ชันการบล็อก

คุณสามารถลงทะเบียนฟังก์ชั่นการบล็อกสำหรับสองเหตุการณ์:

  • beforeCreate : ทริกเกอร์ก่อนที่ผู้ใช้ใหม่จะถูกบันทึกไปยังฐานข้อมูล Firebase Authentication และก่อนที่โทเค็นจะถูกส่งกลับไปยังแอปไคลเอ็นต์ของคุณ

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

โปรดคำนึงถึงสิ่งต่อไปนี้เมื่อใช้ฟังก์ชันการบล็อก:

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

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

  • ฟังก์ชันใช้กับผู้ใช้ทั้งหมดในโครงการของคุณ รวมถึงฟังก์ชันที่มีอยู่ใน ผู้เช่า การตรวจสอบความถูกต้องของ Firebase ให้ข้อมูลเกี่ยวกับผู้ใช้ในฟังก์ชันของคุณ รวมถึงผู้เช่าใดๆ ที่พวกเขาเป็นเจ้าของ ดังนั้นคุณจึงสามารถตอบสนองได้

  • การเชื่อมโยงผู้ให้บริการข้อมูลประจำตัวรายอื่นกับบัญชีจะทริกเกอร์ฟังก์ชัน beforeSignIn ที่ลงทะเบียนไว้อีกครั้ง

  • การรับรองความถูกต้องแบบไม่ระบุชื่อและแบบกำหนดเองจะไม่ทริกเกอร์ฟังก์ชันการบล็อก

ปรับใช้และลงทะเบียนฟังก์ชันการบล็อก

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

ปรับใช้ฟังก์ชันการบล็อก

คุณปรับใช้ฟังก์ชันการบล็อกในลักษณะเดียวกับที่คุณปรับใช้ฟังก์ชันใดๆ (ดูรายละเอียดได้ที่หน้า เริ่มต้นใช้งาน Cloud Functions) สรุป:

  1. เขียน Cloud Functions ที่จัดการเหตุการณ์ beforeCreate , เหตุการณ์ beforeSignIn หรือทั้งสองอย่าง

    ตัวอย่างเช่น ในการเริ่มต้น คุณสามารถเพิ่มฟังก์ชัน no-op ต่อไปนี้ใน index.js :

    const functions = require('firebase-functions');
    
    exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
      // TODO
    });
    
    exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
      // TODO
    });
    

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

  2. ปรับใช้ฟังก์ชันของคุณโดยใช้ Firebase CLI:

    firebase deploy --only functions
    

    คุณต้องปรับใช้ฟังก์ชันของคุณใหม่ทุกครั้งที่คุณอัปเดต

ลงทะเบียนฟังก์ชั่นการปิดกั้น

  1. ไปที่หน้า การตั้งค่า การตรวจสอบความถูกต้องของ Firebase ในคอนโซล Firebase

  2. เลือกแท็บ ฟังก์ชั่นการปิดกั้น

  3. ลงทะเบียนฟังก์ชันการบล็อกของคุณโดยเลือกจากเมนูแบบเลื่อนลงใต้ ก่อนสร้างบัญชี (ก่อนสร้าง) หรือ ก่อนลงชื่อเข้าใช้ (ก่อนลงชื่อเข้าใช้)

  4. บันทึกการเปลี่ยนแปลงของคุณ

รับข้อมูลผู้ใช้และบริบท

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

สำหรับรายการของคุณสมบัติที่มีอยู่ในอ็อบเจกต์ User โปรดดู การอ้างอิง UserRecord API

วัตถุ EventContext มีคุณสมบัติดังต่อไปนี้:

ชื่อ คำอธิบาย ตัวอย่าง
locale ตำแหน่งที่ตั้งของแอปพลิเคชัน คุณสามารถตั้งค่าภาษาโดยใช้ SDK ของไคลเอ็นต์ หรือโดยการส่งส่วนหัวของภาษาใน REST API fr หรือ sv-SE
ipAddress ที่อยู่ IP ของอุปกรณ์ที่ผู้ใช้ปลายทางลงทะเบียนหรือลงชื่อเข้าใช้ 114.14.200.1
userAgent ตัวแทนผู้ใช้ที่ทริกเกอร์ฟังก์ชันการบล็อก Mozilla/5.0 (X11; Linux x86_64)
eventId ตัวระบุเฉพาะของเหตุการณ์ rWsyPtolplG2TBFoOkkgyg
eventType ประเภทเหตุการณ์ ข้อมูลนี้จะให้ข้อมูลเกี่ยวกับชื่อกิจกรรม เช่น beforeSignIn หรือ beforeCreate และวิธีการลงชื่อเข้าใช้ที่เกี่ยวข้อง เช่น Google หรืออีเมล/รหัสผ่าน providers/cloud.auth/eventTypes/user.beforeSignIn:password
authType USER เสมอ USER
resource โครงการ Firebase Authentication หรือผู้เช่า projects/ project-id /tenants/ tenant-id
timestamp เวลาที่เหตุการณ์ถูกทริกเกอร์ ซึ่งจัดรูปแบบเป็นสตริง RFC 3339 Tue, 23 Jul 2019 21:10:57 GMT
additionalUserInfo วัตถุที่มีข้อมูลเกี่ยวกับผู้ใช้ AdditionalUserInfo
credential วัตถุที่มีข้อมูลเกี่ยวกับข้อมูลประจำตัวของผู้ใช้ AuthCredential

การบล็อกการลงทะเบียนหรือการลงชื่อเข้าใช้

หากต้องการบล็อกการลงทะเบียนหรือพยายามลงชื่อเข้าใช้ ให้โยน HttpsError ในฟังก์ชันของคุณ ตัวอย่างเช่น:

โหนด js

throw new functions.auth.HttpsError('permission-denied');

ตารางต่อไปนี้แสดงรายการข้อผิดพลาดที่คุณสามารถแจ้งได้ พร้อมด้วยข้อความแสดงข้อผิดพลาดเริ่มต้น:

ชื่อ รหัส ข้อความ
invalid-argument 400 ลูกค้าระบุอาร์กิวเมนต์ที่ไม่ถูกต้อง
failed-precondition 400 ไม่สามารถดำเนินการคำขอในสถานะระบบปัจจุบัน
out-of-range 400 ลูกค้าระบุช่วงที่ไม่ถูกต้อง
unauthenticated 401 โทเค็น OAuth ขาดหายไป ไม่ถูกต้อง หรือหมดอายุ
permission-denied 403 ลูกค้าไม่ได้รับอนุญาตเพียงพอ
not-found 404 ไม่พบทรัพยากรที่ระบุ
aborted 409 ความขัดแย้งที่เกิดขึ้นพร้อมกัน เช่น ความขัดแย้งในการอ่าน-แก้ไข-เขียน
already-exists 409 ทรัพยากรที่ไคลเอนต์พยายามสร้างมีอยู่แล้ว
resource-exhausted 429 โควต้าทรัพยากรหมดหรือถึงขีดจำกัดอัตรา
cancelled 499 คำขอถูกยกเลิกโดยลูกค้า
data-loss 500 การสูญเสียข้อมูลที่กู้คืนไม่ได้หรือข้อมูลเสียหาย
unknown 500 ข้อผิดพลาดของเซิร์ฟเวอร์ที่ไม่รู้จัก
internal 500 ข้อผิดพลาดภายในเซิร์ฟเวอร์
not-implemented 501 เซิร์ฟเวอร์ไม่ได้ใช้วิธี API
unavailable 503 ไม่สามารถให้บริการได้.
deadline-exceeded 504 เกินกำหนดส่งคำขอแล้ว

คุณยังสามารถระบุข้อความแสดงข้อผิดพลาดที่กำหนดเอง:

โหนด js

throw new functions.auth.HttpsError('permission-denied', 'Unauthorized request origin!');

ตัวอย่างต่อไปนี้แสดงวิธีบล็อกผู้ใช้ที่ไม่ได้อยู่ในโดเมนเฉพาะไม่ให้ลงทะเบียนแอปของคุณ:

โหนด js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  // (If the user is authenticating within a tenant context, the tenant ID can be determined from
  // user.tenantId or from context.resource, e.g. 'projects/project-id/tenant/tenant-id-1')

  // Only users of a specific domain can sign up.
  if (user.email.indexOf('@acme.com') === -1) {
    throw new functions.auth.HttpsError('invalid-argument', `Unauthorized email "${user.email}"`);
  }
});

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

throw new functions.auth.HttpsError('invalid-argument', `Unauthorized email user@evil.com}`);

แอปของคุณควรตรวจจับข้อผิดพลาดและจัดการตามนั้น ตัวอย่างเช่น:

จาวาสคริปต์

// Blocking functions can also be triggered in a multi-tenant context before user creation.
// firebase.auth().tenantId = 'tenant-id-1';
firebase.auth().createUserWithEmailAndPassword('johndoe@example.com', 'password')
  .then((result) => {
    result.user.getIdTokenResult()
  })
  .then((idTokenResult) => {
    console.log(idTokenResult.claim.admin);
  })
  .catch((error) => {
    if (error.code !== 'auth/internal-error' && error.message.indexOf('Cloud Function') !== -1) {
      // Display error.
    } else {
      // Registration succeeds.
    }
  });

การปรับเปลี่ยนผู้ใช้

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

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

  • displayName
  • disabled
  • emailVerified
  • photoURL
  • customClaims
  • sessionClaims ( beforeSignIn เท่านั้น)

ยกเว้น sessionClaims ที่แก้ไขทั้งหมดจะถูกบันทึกลงในฐานข้อมูลของ Firebase Authentication ซึ่งหมายความว่าจะรวมอยู่ในโทเค็นการตอบสนองและคงอยู่ระหว่างเซสชันของผู้ใช้

ตัวอย่างต่อไปนี้แสดงวิธีการตั้งชื่อที่แสดงเริ่มต้น:

โหนด js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  return {
    // If no display name is provided, set it to "Guest".
    displayName: user.displayName || 'Guest';
  };
});

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

ตัวอย่างเช่น หากมีการตั้ง sessionClaims beforeSignIn จะส่งคืนด้วยการอ้างสิทธิ์ beforeCreate และจะมีการรวมเข้าด้วยกัน เมื่อรวมเข้าด้วยกัน หากคีย์ sessionClaims ตรงกับคีย์ใน customClaims customClaims ที่กำหนดเองที่ตรงกันจะถูกเขียนทับในการอ้างสิทธิ์โทเค็นโดยคีย์ sessionClaims อย่างไรก็ตาม คีย์ customClaims ที่ถูกทับจะยังคงอยู่ในฐานข้อมูลสำหรับคำขอในอนาคต

ข้อมูลรับรอง OAuth และข้อมูลที่รองรับ

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

ผู้ให้บริการข้อมูลประจำตัว โทเค็น ID โทเค็นการเข้าถึง เวลาหมดอายุ ความลับของโทเค็น รีเฟรชโทเค็น การอ้างสิทธิ์ในการลงชื่อเข้าใช้
Google ใช่ ใช่ ใช่ เลขที่ ใช่ เลขที่
เฟสบุ๊ค เลขที่ ใช่ ใช่ เลขที่ เลขที่ เลขที่
ทวิตเตอร์ เลขที่ ใช่ เลขที่ ใช่ เลขที่ เลขที่
GitHub เลขที่ ใช่ เลขที่ เลขที่ เลขที่ เลขที่
ไมโครซอฟท์ ใช่ ใช่ ใช่ เลขที่ ใช่ เลขที่
ลิงค์อิน เลขที่ ใช่ ใช่ เลขที่ เลขที่ เลขที่
ยาฮู ใช่ ใช่ ใช่ เลขที่ ใช่ เลขที่
แอปเปิล ใช่ ใช่ ใช่ เลขที่ ใช่ เลขที่
SAML เลขที่ เลขที่ เลขที่ เลขที่ เลขที่ ใช่
คปภ ใช่ ใช่ ใช่ เลขที่ ใช่ ใช่

รีเฟรชโทเค็น

หากต้องการใช้โทเค็นรีเฟรชในฟังก์ชันการบล็อก คุณต้องเลือกช่องทำเครื่องหมายในหน้า ฟังก์ชันการบล็อก ของคอนโซล Firebase ก่อน

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

ส่วนต่อไปนี้จะอธิบายประเภทผู้ให้บริการข้อมูลประจำตัวแต่ละประเภทและข้อมูลประจำตัวและข้อมูลที่รองรับ

ผู้ให้บริการ OIDC ทั่วไป

เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วยผู้ให้บริการ OIDC ทั่วไป ข้อมูลประจำตัวต่อไปนี้จะถูกส่งผ่าน:

  • โทเค็น ID : ระบุหากเลือกโฟลว์ id_token
  • โทเค็นการเข้าถึง : มีให้หากเลือกโฟลว์โค้ด โปรดทราบว่าขณะนี้โค้ดโฟลว์รองรับผ่าน REST API เท่านั้น
  • รีเฟรชโทเค็น : ระบุหากเลือก ขอบเขต offline_access

ตัวอย่าง:

const provider = new firebase.auth.OAuthProvider('oidc.my-provider');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);

Google

เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย Google ข้อมูลรับรองต่อไปนี้จะถูกส่งผ่าน:

  • โทเค็น ID
  • โทเค็นการเข้าถึง
  • โทเค็นการรีเฟรช : ให้เฉพาะเมื่อมีการร้องขอพารามิเตอร์ที่กำหนดเองต่อไปนี้:
    • access_type=offline
    • prompt=consent หากผู้ใช้ให้ความยินยอมก่อนหน้านี้และไม่มีการร้องขอขอบเขตใหม่

ตัวอย่าง:

const provider = new firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({
  'access_type': 'offline',
  'prompt': 'consent'
});
firebase.auth().signInWithPopup(provider);

เรียนรู้เพิ่มเติมเกี่ยวกับ โทเค็นการรีเฟรชของ Google

เฟสบุ๊ค

เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย Facebook ข้อมูลประจำตัวต่อไปนี้จะถูกส่งผ่าน:

  • โทเค็นการเข้าถึง : โทเค็นการเข้าถึงจะถูกส่งคืนซึ่งสามารถแลกเปลี่ยนเป็นโทเค็นการเข้าถึงอื่นได้ เรียนรู้เพิ่มเติมเกี่ยวกับประเภทต่างๆ ของ โทเค็นการเข้าถึง ที่สนับสนุนโดย Facebook และวิธีที่คุณสามารถแลกเปลี่ยนเป็น โทเค็นที่มีอายุยืน

GitHub

เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย GitHub ข้อมูลรับรองต่อไปนี้จะถูกส่งผ่าน:

  • โทเค็นการเข้าถึง : ไม่หมดอายุเว้นแต่จะถูกเพิกถอน

ไมโครซอฟท์

เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย Microsoft ข้อมูลรับรองต่อไปนี้จะถูกส่งผ่าน:

  • โทเค็น ID
  • โทเค็นการเข้าถึง
  • รีเฟรชโทเค็น : ส่งผ่านไปยังฟังก์ชันการบล็อกหากเลือก ขอบเขต offline_access

ตัวอย่าง:

const provider = new firebase.auth.OAuthProvider('microsoft.com');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);

ยาฮู

เมื่อผู้ใช้ลงชื่อเข้าใช้ Yahoo ข้อมูลประจำตัวต่อไปนี้จะถูกส่งผ่านโดยไม่มีพารามิเตอร์หรือขอบเขตที่กำหนดเอง:

  • โทเค็น ID
  • โทเค็นการเข้าถึง
  • รีเฟรชโทเค็น

ลิงค์อิน

เมื่อผู้ใช้ลงชื่อเข้าใช้ LinkedIn ข้อมูลรับรองต่อไปนี้จะถูกส่งผ่าน:

  • โทเค็นการเข้าถึง

แอปเปิล

เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย Apple ข้อมูลรับรองต่อไปนี้จะถูกส่งผ่านโดยไม่มีพารามิเตอร์หรือขอบเขตที่กำหนดเอง:

  • โทเค็น ID
  • โทเค็นการเข้าถึง
  • รีเฟรชโทเค็น

สถานการณ์ทั่วไป

ตัวอย่างต่อไปนี้แสดงกรณีการใช้งานทั่วไปสำหรับฟังก์ชันการบล็อก:

อนุญาตให้ลงทะเบียนจากโดเมนที่ระบุเท่านั้น

ตัวอย่างต่อไปนี้แสดงวิธีป้องกันไม่ให้ผู้ใช้ที่ไม่ได้เป็นส่วนหนึ่งของโดเมน example.com ลงทะเบียนกับแอปของคุณ:

โหนด js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (!user.email || user.email.indexOf('@example.com') === -1) {
    throw new functions.auth.HttpsError(
      'invalid-argument', `Unauthorized email "${user.email}"`);
  }
});

บล็อกผู้ใช้ที่มีอีเมลที่ไม่ได้รับการยืนยันไม่ให้ลงทะเบียน

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

โหนด js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (user.email && !user.emailVerified) {
    throw new functions.auth.HttpsError(
      'invalid-argument', `Unverified email "${user.email}"`);
  }
});

ต้องการการยืนยันอีเมลในการลงทะเบียน

ตัวอย่างต่อไปนี้แสดงวิธีกำหนดให้ผู้ใช้ยืนยันอีเมลหลังจากลงทะเบียน:

โหนด js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  const locale = context.locale;
  if (user.email && !user.emailVerified) {
    // Send custom email verification on sign-up.
    return admin.auth().generateEmailVerificationLink(user.email).then((link) => {
      return sendCustomVerificationEmail(user.email, link, locale);
    });
  }
});

exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
 if (user.email && !user.emailVerified) {
   throw new functions.auth.HttpsError(
     'invalid-argument', `"${user.email}" needs to be verified before access is granted.`);
  }
});

การปฏิบัติต่ออีเมลของผู้ให้บริการข้อมูลประจำตัวบางอย่างว่าได้รับการยืนยันแล้ว

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

โหนด js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (user.email && !user.emailVerified && context.eventType.indexOf(':facebook.com') !== -1) {
    return {
      emailVerified: true,
    };
  }
});

การบล็อกการลงชื่อเข้าใช้จากที่อยู่ IP บางอย่าง

ตัวอย่างต่อไปนี้บล็อกการลงชื่อเข้าใช้จากช่วงที่อยู่ IP บางช่วง:

โหนด js

exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
  if (isSuspiciousIpAddress(context.ipAddress)) {
    throw new functions.auth.HttpsError(
      'permission-denied', 'Unauthorized access!');
  }
});

การตั้งค่าแบบกำหนดเองและการอ้างสิทธิ์เซสชัน

ตัวอย่างต่อไปนี้แสดงวิธีการตั้งค่าแบบกำหนดเองและการอ้างสิทธิ์เซสชัน:

โหนด js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (context.credential &&
      context.credential.providerId === 'saml.my-provider-id') {
    return {
      // Employee ID does not change so save in persistent claims (stored in
      // Auth DB).
      customClaims: {
        eid: context.credential.claims.employeeid,
      },
      // Copy role and groups to token claims. These will not be persisted.
      sessionClaims: {
        role: context.credential.claims.role,
        groups: context.credential.claims.groups,
      }
    }
  }
});

ติดตามที่อยู่ IP เพื่อตรวจสอบกิจกรรมที่น่าสงสัย

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

  1. ใช้การอ้างสิทธิ์เซสชันเพื่อติดตามที่อยู่ IP ที่ผู้ใช้ลงชื่อเข้าใช้:

    โหนด js

    exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
      return {
        sessionClaims: {
          signInIpAddress: context.ipAddress,
        },
      };
    });
    
  2. เมื่อผู้ใช้พยายามเข้าถึงทรัพยากรที่ต้องการการตรวจสอบสิทธิ์ด้วย Firebase Authentication ให้เปรียบเทียบที่อยู่ IP ในคำขอกับ IP ที่ใช้ในการลงชื่อเข้าใช้:

    โหนด js

    app.post('/getRestrictedData', (req, res) => {
      // Get the ID token passed.
      const idToken = req.body.idToken;
      // Verify the ID token, check if revoked and decode its payload.
      admin.auth().verifyIdToken(idToken, true).then((claims) => {
        // Get request IP address
        const requestIpAddress = req.connection.remoteAddress;
        // Get sign-in IP address.
        const signInIpAddress = claims.signInIpAddress;
        // Check if the request IP address origin is suspicious relative to
        // the session IP addresses. The current request timestamp and the
        // auth_time of the ID token can provide additional signals of abuse,
        // especially if the IP address suddenly changed. If there was a sudden
        // geographical change in a short period of time, then it will give
        // stronger signals of possible abuse.
        if (!isSuspiciousIpAddressChange(signInIpAddress, requestIpAddress)) {
          // Suspicious IP address change. Require re-authentication.
          // You can also revoke all user sessions by calling:
          // admin.auth().revokeRefreshTokens(claims.sub).
          res.status(401).send({error: 'Unauthorized access. Please login again!'});
        } else {
          // Access is valid. Try to return data.
          getData(claims).then(data => {
            res.end(JSON.stringify(data);
          }, error => {
            res.status(500).send({ error: 'Server error!' })
          });
        }
      });
    });
    

คัดกรองภาพถ่ายของผู้ใช้

ตัวอย่างต่อไปนี้แสดงวิธีฆ่าเชื้อรูปโปรไฟล์ของผู้ใช้:

โหนด js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (user.photoURL) {
    return isPhotoAppropriate(user.photoURL)
      .then((status) => {
        if (!status) {
          // Sanitize inappropriate photos by replacing them with guest photos.
          // Users could also be blocked from sign-up, disabled, etc.
          return {
            photoURL: PLACEHOLDER_GUEST_PHOTO_URL,
          };
        }
      });
});

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีตรวจจับและฆ่าเชื้อภาพ โปรดดูเอกสารประกอบของ Cloud Vision

การเข้าถึงข้อมูลรับรอง OAuth ของผู้ให้บริการข้อมูลประจำตัวของผู้ใช้

ตัวอย่างต่อไปนี้สาธิตวิธีรับโทเค็นการรีเฟรชสำหรับผู้ใช้ที่ลงชื่อเข้าใช้ด้วย Google และใช้เพื่อเรียกใช้ Google Calendar API โทเค็นการรีเฟรชถูกเก็บไว้สำหรับการเข้าถึงแบบออฟไลน์

โหนด js

const {OAuth2Client} = require('google-auth-library');
const {google} = require('googleapis');
// ...
// Initialize Google OAuth client.
const keys = require('./oauth2.keys.json');
const oAuth2Client = new OAuth2Client(
  keys.web.client_id,
  keys.web.client_secret
);

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (context.credential &&
      context.credential.providerId === 'google.com') {
    // Store the refresh token for later offline use.
    // These will only be returned if refresh tokens credentials are included
    // (enabled by Cloud console).
    return saveUserRefreshToken(
        user.uid,
        context.credential.refreshToken,
        'google.com'
      )
      .then(() => {
        // Blocking the function is not required. The function can resolve while
        // this operation continues to run in the background.
        return new Promise((resolve, reject) => {
          // For this operation to succeed, the appropriate OAuth scope should be requested
          // on sign in with Google, client-side. In this case:
          // https://www.googleapis.com/auth/calendar
          // You can check granted_scopes from within:
          // context.additionalUserInfo.profile.granted_scopes (space joined list of scopes).

          // Set access token/refresh token.
          oAuth2Client.setCredentials({
            access_token: context.credential.accessToken,
            refresh_token: context.credential.refreshToken,
          });
          const calendar = google.calendar('v3');
          // Setup Onboarding event on user's calendar.
          const event = {/** ... */};
          calendar.events.insert({
            auth: oauth2client,
            calendarId: 'primary',
            resource: event,
          }, (err, event) => {
            // Do not fail. This is a best effort approach.
            resolve();
          });
      });
    })
  }
});