ขยายการรับรองความถูกต้องของ Firebase ด้วยฟังก์ชันการบล็อก


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  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
    

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

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

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

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

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

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

  • โทเค็นประจำตัว
  • โทเค็นการเข้าถึง
  • โทเค็นการรีเฟรช : มีให้เฉพาะเมื่อมีการร้องขอพารามิเตอร์ที่กำหนดเองต่อไปนี้:
    • 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 ข้อมูลประจำตัวต่อไปนี้จะถูกส่งไป:

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

ตัวอย่าง:

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

ยาฮู

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

  • โทเค็นประจำตัว
  • โทเค็นการเข้าถึง
  • รีเฟรชโทเค็น

ลิงค์อิน

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

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

แอปเปิล

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

  • โทเค็นประจำตัว
  • โทเค็นการเข้าถึง
  • รีเฟรชโทเค็น

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

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

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

ตัวอย่างต่อไปนี้แสดงวิธีป้องกันไม่ให้ผู้ใช้ที่ไม่ได้เป็นส่วนหนึ่งของโดเมน 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();
          });
      });
    })
  }
});

ลบล้างคำตัดสินของ reCAPTCHA Enterprise สำหรับการดำเนินการของผู้ใช้

ตัวอย่างต่อไปนี้แสดงวิธีลบล้างคำตัดสิน reCAPTCHA Enterprise สำหรับโฟลว์ผู้ใช้ที่รองรับ

โปรดดูที่ เปิดใช้งาน reCAPTCHA Enterprise เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับการผสานรวม reCAPTCHA Enterprise เข้ากับการตรวจสอบสิทธิ์ Firebase

ฟังก์ชันการบล็อกสามารถใช้เพื่ออนุญาตหรือบล็อกโฟลว์ตามปัจจัยที่กำหนดเองได้ ดังนั้นจึงแทนที่ผลลัพธ์ที่ได้รับจาก reCAPTCHA Enterprise

โหนด js

 const {
   auth,
 } = require("firebase-functions/v1");

exports.checkrecaptchaV1 = auth.user().beforeSignIn((userRecord, context) => {
 // Allow users with a specific email domain to sign in regardless of their recaptcha score.
 if (userRecord.email && userRecord.email.indexOf('@acme.com') === -1) {
   return {
     recaptchaActionOverride: 'ALLOW',
   };
 }

 // Allow users to sign in with recaptcha score greater than 0.5
 if (context.additionalUserInfo.recaptchaScore > 0.5) {
   return {
     recaptchaActionOverride: 'ALLOW',
   };
 }

 // Block all others.
 return {
   recaptchaActionOverride: 'BLOCK',
 };
});