Firebase is back at Google I/O on May 10! Register now

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

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

หากคุณได้อัปเกรดเป็น Firebase Authentication ด้วย Identity Platform คุณสามารถขยาย Firebase Authentication โดยใช้การปิดกั้น Cloud Functions

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

ก่อนจะเริ่ม

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. เขียนฟังก์ชันระบบคลาวด์ที่จัดการเหตุการณ์ 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. ลงทะเบียนฟังก์ชันการบล็อกของคุณโดยเลือกจากเมนูดรอปดาวน์ภายใต้ ก่อนการสร้างบัญชี (beforeCreate) หรือ Before sign in (beforeSignIn)

  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 หรือผู้เช่า projects/ project-id /tenants/ tenant-id
timestamp เวลาที่เหตุการณ์ถูกทริกเกอร์ โดยจัดรูปแบบเป็นสตริง RFC 3339 Tue, 23 Jul 2019 21:10:57 GMT
additionalUserInfo วัตถุที่มีข้อมูลเกี่ยวกับผู้ใช้ AdditionalUserInfo
credential อ็อบเจ็กต์ที่มีข้อมูลเกี่ยวกับหนังสือรับรองของผู้ใช้ AuthCredential

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

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

Node.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 เกินกำหนดส่งคำขอ

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

Node.js

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

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

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

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

JavaScript

// 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 ซึ่งหมายความว่าจะรวมอยู่ในโทเค็นการตอบกลับและคงอยู่ระหว่างเซสชันของผู้ใช้

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

Node.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 ที่ overwitten จะยังคงอยู่ในฐานข้อมูลสำหรับการร้องขอในอนาคต

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

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

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

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

หากต้องการใช้โทเค็นการรีเฟรชในฟังก์ชันการบล็อก คุณต้องเลือกช่องทำเครื่องหมายในหน้า ฟังก์ชันการบล็อก ของคอนโซล 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 ข้อมูลประจำตัวต่อไปนี้จะถูกส่งต่อ:

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

GitHub

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

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

Microsoft

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

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

ตัวอย่าง:

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

Yahoo

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

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

LinkedIn

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

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

แอปเปิล

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Node.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 บางช่วง:

Node.js

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

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

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

Node.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 ที่ผู้ใช้ลงชื่อเข้าใช้ด้วย:

    Node.js

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

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

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

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

Node.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 โทเค็นการรีเฟรชถูกเก็บไว้สำหรับการเข้าถึงแบบออฟไลน์

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