ฟังก์ชันการบล็อกช่วยให้คุณเรียกใช้โค้ดที่กำหนดเองซึ่งจะแก้ไขผลลัพธ์จากการที่ผู้ใช้ลงทะเบียนหรือลงชื่อเข้าใช้แอปของคุณ เช่น คุณสามารถป้องกันไม่ให้ผู้ใช้ตรวจสอบสิทธิ์หากผู้ใช้ไม่ตรงตามเกณฑ์ที่กำหนด หรืออัปเดตข้อมูลของผู้ใช้ก่อนที่จะส่งคืนไปยังแอปไคลเอ็นต์ของคุณ
ก่อนเริ่มต้น
หากต้องการใช้ฟังก์ชันการบล็อก คุณต้องอัปเกรดโปรเจ็กต์ Firebase เป็นการตรวจสอบสิทธิ์ Firebase ด้วย Identity Platform หากคุณยังไม่ได้อัปเกรด โปรดอัปเกรดก่อน
การทำความเข้าใจฟังก์ชันการบล็อก
คุณลงทะเบียนฟังก์ชันการบล็อกได้ 2 เหตุการณ์ ดังนี้
beforeCreate
: ทริกเกอร์ก่อนบันทึกผู้ใช้ใหม่ไปยังฐานข้อมูลการตรวจสอบสิทธิ์ Firebase และก่อนส่งโทเค็นไปยังแอปไคลเอ็นต์beforeSignIn
: ทริกเกอร์หลังจากยืนยันข้อมูลเข้าสู่ระบบของผู้ใช้แล้ว แต่ก่อนที่การตรวจสอบสิทธิ์ Firebase จะส่งโทเค็นรหัสไปยังแอปไคลเอ็นต์ หากแอปใช้การตรวจสอบสิทธิ์แบบหลายปัจจัย ฟังก์ชันดังกล่าวจะทริกเกอร์หลังจากที่ผู้ใช้ยืนยันปัจจัยที่ 2 แล้ว โปรดทราบว่าการสร้างผู้ใช้ใหม่จะทริกเกอร์beforeSignIn
ด้วย นอกเหนือจากbeforeCreate
โปรดคำนึงถึงสิ่งต่อไปนี้เมื่อใช้ฟังก์ชันการบล็อก
ฟังก์ชันของคุณต้องตอบสนองภายใน 7 วินาที หลังผ่านไป 7 วินาที การตรวจสอบสิทธิ์ Firebase จะแสดงข้อผิดพลาด และการดำเนินการไคลเอ็นต์ล้มเหลว
ระบบจะส่งโค้ดตอบกลับ HTTP อื่นที่ไม่ใช่
200
ไปยังแอปไคลเอ็นต์ของคุณ ตรวจสอบว่ารหัสไคลเอ็นต์จัดการข้อผิดพลาดที่ฟังก์ชันอาจแสดงผลได้ฟังก์ชันจะมีผลกับผู้ใช้ทั้งหมดในโปรเจ็กต์ รวมถึงผู้ใช้ที่อยู่ในกลุ่มผู้ใช้ การตรวจสอบสิทธิ์ Firebase ให้ข้อมูลเกี่ยวกับผู้ใช้ในฟังก์ชัน รวมถึงกลุ่มผู้ใช้เหล่านั้นเพื่อให้คุณตอบกลับได้อย่างสอดคล้องกัน
การลิงก์ผู้ให้บริการข้อมูลประจำตัวรายอื่นกับบัญชีจะทริกเกอร์ฟังก์ชัน
beforeSignIn
ที่ลงทะเบียนไว้อีกครั้งการตรวจสอบสิทธิ์แบบกำหนดเองและไม่ระบุตัวตนจะไม่เรียกใช้ฟังก์ชันการบล็อก
ทำให้ฟังก์ชันการบล็อกใช้งานได้
หากต้องการแทรกโค้ดที่กำหนดเองลงในขั้นตอนการตรวจสอบสิทธิ์ผู้ใช้ ให้ทำให้ฟังก์ชันการบล็อกใช้งานได้ เมื่อใช้ฟังก์ชันการบล็อกแล้ว โค้ดที่กำหนดเองจะต้องเสร็จสมบูรณ์เพื่อให้การตรวจสอบสิทธิ์และการสร้างผู้ใช้ประสบความสำเร็จ
คุณทำให้ฟังก์ชันการบล็อกใช้งานได้ในลักษณะเดียวกับการทำให้ฟังก์ชันใดๆ ใช้งานได้ (ดูรายละเอียดในหน้าการเริ่มต้นใช้งาน Cloud Functions) บทสรุปมีดังนี้:
เขียน Cloud Functions ที่จัดการเหตุการณ์
beforeCreate
, เหตุการณ์beforeSignIn
หรือทั้ง 2 อย่างตัวอย่างเช่น ในการเริ่มต้นใช้งาน คุณสามารถเพิ่มฟังก์ชันที่ไม่มีการดำเนินการต่อไปนี้ลงใน
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 });
ตัวอย่างข้างต้นไม่ได้นำตรรกะการตรวจสอบสิทธิ์ที่กำหนดเองมาใช้งาน ดูวิธีการใช้ฟังก์ชันการบล็อกและสถานการณ์ที่พบบ่อยสำหรับตัวอย่างที่เฉพาะเจาะจงได้ที่ส่วนต่อไปนี้
ทำให้ฟังก์ชันใช้งานได้โดยใช้ Firebase CLI ดังนี้
firebase deploy --only functions
คุณต้องทำให้ฟังก์ชันใช้งานได้อีกครั้งทุกครั้งที่อัปเดต
กำลังรับข้อมูลผู้ใช้และบริบท
เหตุการณ์ beforeSignIn
และ beforeCreate
มีออบเจ็กต์ User
และ EventContext
ที่มีข้อมูลเกี่ยวกับผู้ใช้ที่ลงชื่อเข้าใช้ ใช้ค่าเหล่านี้ในโค้ดเพื่อกำหนดว่าจะอนุญาตให้ดำเนินการต่อไปหรือไม่
ดูรายการพร็อพเพอร์ตี้ที่มีอยู่ในออบเจ็กต์ User
ได้ที่ข้อมูลอ้างอิง API ของ UserRecord
ออบเจ็กต์ EventContext
มีพร็อพเพอร์ตี้ต่อไปนี้
ชื่อ | คำอธิบาย | ตัวอย่าง |
---|---|---|
locale |
ภาษาของแอปพลิเคชัน คุณตั้งค่าภาษาได้โดยใช้ SDK ของไคลเอ็นต์ หรือส่งส่วนหัวของภาษาใน REST API | fr หรือ sv-SE |
ipAddress
| ที่อยู่ IP ของอุปกรณ์ที่ผู้ใช้ปลายทางลงทะเบียนหรือลงชื่อเข้าใช้ | 114.14.200.1 |
userAgent
| User Agent ที่ทริกเกอร์ฟังก์ชันการบล็อก | 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 |
ความขัดแย้งในการดำเนินการพร้อมกัน เช่น ความขัดแย้งแบบ Read-modify-write |
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 และส่งกลับไปยังไคลเอ็นต์
หากต้องการแก้ไขผู้ใช้ ให้แสดงผลออบเจ็กต์จากเครื่องจัดการเหตุการณ์ที่มีช่องที่ต้องการแก้ไข คุณจะแก้ไขช่องต่อไปนี้ได้
displayName
disabled
emailVerified
photoUrl
customClaims
sessionClaims
(beforeSignIn
เท่านั้น)
ฟิลด์ที่แก้ไขทั้งหมดจะได้รับการบันทึกไว้ในฐานข้อมูลของการตรวจสอบสิทธิ์ Firebase ซึ่งหมายความว่าฟิลด์เหล่านั้นจะรวมอยู่ในโทเค็นตอบกลับและคงอยู่ตลอดเซสชันผู้ใช้sessionClaims
ตัวอย่างต่อไปนี้แสดงวิธีตั้งชื่อที่แสดงเริ่มต้น
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
ในตัวแฮนเดิลเหตุการณ์ทั้ง 2 แบบ ค่าที่ตั้งไว้ใน beforeSignIn
จะเขียนทับค่าที่ตั้งไว้ใน beforeCreate
สำหรับ sessionClaims
เท่านั้น ข้อมูลดังกล่าวจะมีการนำไปเผยแพร่กับการอ้างสิทธิ์โทเค็นของเซสชันปัจจุบัน แต่จะไม่คงอยู่หรือจัดเก็บไว้ในฐานข้อมูล
ตัวอย่างเช่น หากตั้งค่า sessionClaims
ไว้ beforeSignIn
จะส่งผลลัพธ์ที่มีการอ้างสิทธิ์ beforeCreate
รายการขึ้นมาและจะรวมเข้าด้วยกัน เมื่อผสานรวมกัน หากคีย์ sessionClaims
ตรงกับคีย์ใน customClaims
ระบบจะเขียนทับ customClaims
ที่ตรงกันในการอ้างสิทธิ์โทเค็นด้วยคีย์ sessionClaims
อย่างไรก็ตาม คีย์ customClaims
ที่ถูกแทนที่จะยังคงอยู่ในฐานข้อมูลสำหรับคำขอในอนาคต
ข้อมูลเข้าสู่ระบบ OAuth และข้อมูลที่รองรับ
คุณส่งข้อมูลเข้าสู่ระบบและข้อมูล OAuth ไปยังการบล็อกฟังก์ชันจากผู้ให้บริการข้อมูลประจำตัวรายต่างๆ ได้ ตารางต่อไปนี้แสดงข้อมูลเข้าสู่ระบบและข้อมูลที่รองรับสำหรับผู้ให้บริการข้อมูลประจำตัวแต่ละราย
ผู้ให้บริการข้อมูลประจำตัว | โทเค็นรหัส | โทเค็นเพื่อการเข้าถึง | เวลาหมดอายุ | ข้อมูลลับของโทเค็น | โทเค็นการรีเฟรช | การอ้างสิทธิ์ในการลงชื่อเข้าใช้ |
---|---|---|---|---|---|---|
ใช่ | ใช่ | ใช่ | ไม่ได้ | ใช่ | ไม่ได้ | |
ไม่ได้ | ใช่ | ใช่ | ไม่ได้ | ไม่ได้ | ไม่ได้ | |
ไม่ได้ | ใช่ | ไม่ได้ | ใช่ | ไม่ได้ | ไม่ได้ | |
GitHub | ไม่ได้ | ใช่ | ไม่ได้ | ไม่ได้ | ไม่ได้ | ไม่ได้ |
Microsoft | ใช่ | ใช่ | ใช่ | ไม่ได้ | ใช่ | ไม่ได้ |
ไม่ได้ | ใช่ | ใช่ | ไม่ได้ | ไม่ได้ | ไม่ได้ | |
Yahoo | ใช่ | ใช่ | ใช่ | ไม่ได้ | ใช่ | ไม่ได้ |
Apple | ใช่ | ใช่ | ใช่ | ไม่ได้ | ใช่ | ไม่ได้ |
SAML | ไม่ได้ | ไม่ได้ | ไม่ได้ | ไม่ได้ | ไม่ได้ | ใช่ |
OIDC | ใช่ | ใช่ | ใช่ | ไม่ได้ | ใช่ | ใช่ |
รีเฟรชโทเค็น
หากต้องการใช้โทเค็นการรีเฟรชในฟังก์ชันการบล็อก คุณต้องเลือกช่องทำเครื่องหมายในหน้าฟังก์ชันการบล็อกของคอนโซล Firebase ก่อน
ผู้ให้บริการข้อมูลประจำตัวจะไม่แสดงผลโทเค็นการรีเฟรชเมื่อลงชื่อเข้าใช้โดยตรงด้วยข้อมูลเข้าสู่ระบบ OAuth เช่น โทเค็นรหัสหรือโทเค็นเพื่อการเข้าถึง ในกรณีนี้ ระบบจะส่งข้อมูลเข้าสู่ระบบ OAuth ฝั่งไคลเอ็นต์เดียวกันไปยังฟังก์ชันการบล็อก
ส่วนต่อไปนี้จะอธิบายผู้ให้บริการข้อมูลประจำตัวแต่ละประเภท รวมถึงข้อมูลเข้าสู่ระบบและข้อมูลที่รองรับ
ผู้ให้บริการ OIDC ทั่วไป
เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วยผู้ให้บริการ OIDC ทั่วไป ระบบจะส่งข้อมูลเข้าสู่ระบบต่อไปนี้
- โทเค็นรหัส: ระบุหากเลือกขั้นตอน
id_token
- โทเค็นเพื่อการเข้าถึง: ระบุไว้หากเลือกโฟลว์ของโค้ด โปรดทราบว่าขณะนี้รองรับโฟลว์โค้ดผ่าน REST API เท่านั้น
- โทเค็นการรีเฟรช: ระบุหากเลือกขอบเขต
offline_access
เช่น
const provider = new firebase.auth.OAuthProvider('oidc.my-provider');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);
เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย 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
เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย Microsoft ระบบจะส่งข้อมูลเข้าสู่ระบบต่อไปนี้
- โทเค็นรหัส
- โทเค็นเพื่อการเข้าถึง
- โทเค็นการรีเฟรช: ส่งผ่านไปยังฟังก์ชันการบล็อกหากเลือกขอบเขต
offline_access
เช่น
const provider = new firebase.auth.OAuthProvider('microsoft.com');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);
Yahoo
เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย Yahoo ระบบจะส่งข้อมูลเข้าสู่ระบบต่อไปนี้โดยไม่มีพารามิเตอร์หรือขอบเขตที่กำหนดเอง
- โทเค็นรหัส
- โทเค็นเพื่อการเข้าถึง
- โทเค็นการรีเฟรช
เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย LinkedIn ระบบจะส่งข้อมูลเข้าสู่ระบบต่อไปนี้
- โทเค็นเพื่อการเข้าถึง
Apple
เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วย Apple ระบบจะส่งข้อมูลเข้าสู่ระบบต่อไปนี้โดยไม่มีพารามิเตอร์หรือขอบเขตที่กำหนดเอง
- โทเค็นรหัส
- โทเค็นเพื่อการเข้าถึง
- โทเค็นการรีเฟรช
สถานการณ์ที่พบบ่อย
ตัวอย่างต่อไปนี้แสดง Use Case ที่พบบ่อยสำหรับฟังก์ชันการบล็อก
อนุญาตให้จดทะเบียนจากโดเมนที่เจาะจงเท่านั้น
ตัวอย่างต่อไปนี้แสดงวิธีป้องกันไม่ให้ผู้ใช้ที่ไม่ได้อยู่ในโดเมน 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 มาจากภูมิภาคทางภูมิศาสตร์อื่นๆ คุณขอให้ผู้ใช้ลงชื่อเข้าใช้อีกครั้งได้
ใช้การอ้างสิทธิ์เซสชันเพื่อติดตามที่อยู่ IP ที่ผู้ใช้ลงชื่อเข้าใช้
Node.js
exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => { return { sessionClaims: { signInIpAddress: context.ipAddress, }, }; });
เมื่อผู้ใช้พยายามเข้าถึงทรัพยากรที่ต้องมีการตรวจสอบสิทธิ์ด้วยการตรวจสอบสิทธิ์ Firebase ให้เปรียบเทียบที่อยู่ 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 และใช้เพื่อเรียกใช้ API ของ Google ปฏิทิน ระบบจะจัดเก็บโทเค็นการรีเฟรชสำหรับการเข้าถึงแบบออฟไลน์
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();
});
});
})
}
});
ลบล้างคำตัดสิน reCAPTCHA Enterprise สำหรับการดำเนินการของผู้ใช้
ตัวอย่างต่อไปนี้แสดงวิธีลบล้างผลการตัดสิน reCAPTCHA Enterprise สําหรับโฟลว์ผู้ใช้ที่รองรับ
โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับการผสานรวม reCAPTCHA Enterprise กับการตรวจสอบสิทธิ์ Firebase ที่หัวข้อเปิดใช้ reCAPTCHA Enterprise
คุณใช้ฟังก์ชันการบล็อกเพื่ออนุญาตหรือบล็อกโฟลว์โดยอิงตามปัจจัยที่กำหนดเองได้ ซึ่งจะลบล้างผลลัพธ์ที่ได้รับจาก reCAPTCHA Enterprise
Node.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',
};
});