توابع مسدودسازی به شما امکان میدهند کد سفارشی را اجرا کنید که نتیجه ثبتنام یا ورود کاربر به برنامه شما را تغییر میدهد. برای مثال، میتوانید از اصالتسنجی کاربر درصورت عدم رعایت معیارهای خاص جلوگیری کنید، یا اطلاعات کاربر را قبلاز بازگرداندن آن به برنامه مشتری خود بهروز کنید.
قبل از شروع
برای استفاده از توابع مسدودسازی، باید پروژه Firebase خود را به Firebase Authentication with Identity Platform ارتقا دهید. اگر قبلاً ارتقا ندادهاید، ابتدا این کار را انجام دهید.
آشنایی با توابع مسدودسازی
میتوانید توابع مسدودسازی را برای این رویدادها ثبت کنید:
قبلاز ایجاد کاربر: قبلاز ذخیره شدن کاربر جدید در پایگاه داده Firebase Authentication و قبلاز برگرداندن یک نمانه به برنامه کارخواه شما، راهاندازی میشود.
قبلاز ورود کاربر به سیستم: پساز درستیسنجی اطلاعات اعتباری کاربر راهاندازی میشود، اما قبلاز اینکه Firebase Authentication کد شناسه را به برنامه کارخواه شما برگرداند. اگر برنامه شما از اصالتسنجی چندعاملی استفاده میکند، این تابع پساز درستیسنجی عامل دوم توسط کاربر راهاندازی میشود. توجه داشته باشید که ایجاد کاربر جدید نیز هر دو این رویدادها را راهاندازی میکند.
قبلاز ارسال ایمیل (فقط Node.js): قبلاز ارسال ایمیل (برای مثال، ایمیل ورود به سیستم یا بازنشانی گذرواژه) به کاربر، راهاندازی میشود.
قبلاز ارسال پیامک (فقط Node.js): قبلاز ارسال پیامک به کاربر، برای مواردی مانند اصالتسنجی چندعاملی، راهاندازی میشود.
هنگام استفاده از توابع مسدودسازی، موارد زیر را درنظر داشته باشید:
تابع شما باید ظرف ۷ ثانیه پاسخ دهد. پساز ۷ ثانیه، Firebase Authentication خطا برمیگرداند و عملیات کارخواه ناموفق میشود.
کدهای پاسخ HTTP بهغیراز
200به برنامههای مشتری شما ارسال میشود. مطمئن شوید کد کارخواه شما هرگونه خطایی را که تابع شما میتواند برگرداند مدیریت میکند.توابع برای همه کاربران پروژه شما اعمال میشود، ازجمله هر کاربری که در یک مستأجر قرار دارد. Firebase Authentication اطلاعاتی درباره کاربران به تابع شما ارائه میدهد، ازجمله هر مستأجری که به آن تعلق دارند، تا بتوانید بهطور مقتضی پاسخ دهید.
پیوند دادن ارائهدهنده هویت دیگری به حساب، هرگونه تابع
beforeUserSignedInثبتشده را دوباره راهاندازی میکند.اصالتسنجی ناشناس و سفارشی باعث راهاندازی عملکردهای مسدودسازی نمیشود.
پیادهسازی تابع مسدودسازی
برای درج کد سفارشیتان در جریانهای اصالتسنجی کاربر، توابع مسدودسازی را مستقر کنید. پساز استقرار عملکردهای مسدودسازی، کد سفارشی شما باید باموفقیت تکمیل شود تا اصالتسنجی و ایجاد کاربر با موفقیت انجام شود.
تابع مسدودسازی را به همان روشی که هر تابع دیگری را مستقر میکنید، مستقر میکنید. (برای جزئیات، به صفحه Cloud Functions شروع به کار مراجعه کنید). بهطور خلاصه:
تابعی بنویسید که رویداد هدف را مدیریت کند.
برای مثال، برای شروع، میتوانید تابع بدون عملیاتی مانند تابع زیر را به منبع خود اضافه کنید:
Node.js
import { beforeUserCreated, } from "firebase-functions/v2/identity"; export const beforecreated = beforeUserCreated((event) => { // TODO return; });پایتون
@identity_fn.before_user_created() def created_noop( event: identity_fn.AuthBlockingEvent, ) -> identity_fn.BeforeCreateResponse | None: returnمثال بالا پیادهسازی منطق اصالتسنجی سفارشی را حذف کرده است. برای آشنایی با نحوه پیادهسازی توابع مسدودسازی، بخشهای زیر را ببینید و برای نمونههای خاص، به سناریوهای رایج مراجعه کنید.
توابع خود را بااستفاده از Firebase CLI مستقر کنید:
firebase deploy --only functionsهر بار که توابع خود را بهروز میکنید، باید آنها را دوباره مستقر کنید.
درحال دریافت اطلاعات کاربر و بافت
رویدادهای مسدودکننده یک شیء AuthBlockingEvent ارائه میدهند که حاوی اطلاعاتی درباره کاربر واردشده به سیستم است. از این مقادیر
در کدتان استفاده کنید تا مشخص شود آیا عملیات میتواند ادامه یابد یا نه.
این شیء حاوی ویژگیهای زیر است:
| نام | شرح | مثال |
|---|---|---|
locale |
منطقه زبانی برنامه. میتوانید بااستفاده از کیت توسعه نرمافزار کارخواه یا با ارسال سرصفحه منطقه زبانی در 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 در تابع خود ایجاد کنید. برای مثال:
Node.js
import { HttpsError } from "firebase-functions/v2/identity";
throw new HttpsError('invalid-argument');
پایتون
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT)
همچنین میتوانید پیام خطای سفارشی مشخص کنید:
Node.js
throw new HttpsError('permission-denied', 'Unauthorized request origin!');
پایتون
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.PERMISSION_DENIED,
message="Unauthorized request origin!"
)
مثال زیر نشان میدهد که چگونه کاربرانی را که در دامنه خاصی نیستند از ثبتنام در برنامهتان مسدود کنید:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
// (If the user is authenticating within a tenant context, the tenant ID can be determined from
// user.tenantId or from event.resource, e.g. 'projects/project-id/tenant/tenant-id-1')
// Only users of a specific domain can sign up.
if (!user?.email?.includes('@acme.com')) {
throw new HttpsError('invalid-argument', "Unauthorized email");
}
});
پایتون
# Block account creation with any non-acme email address.
@identity_fn.before_user_created()
def validatenewuser(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
# User data passed in from the CloudEvent.
user = event.data
# Only users of a specific domain can sign up.
if user.email is None or "@acme.com" not in user.email:
# Return None so that Firebase Auth rejects the account creation.
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
message="Unauthorized email",
)
صرفنظر از اینکه از پیام پیشفرض یا سفارشی استفاده میکنید، Cloud Functions خطا را بستهبندی میکند و آن را بهعنوان خطای داخلی به کارخواه برمیگرداند. برای مثال:
Node.js
throw new HttpsError('invalid-argument', "Unauthorized email");
پایتون
# Only users of a specific domain can sign up.
if user.email is None or "@acme.com" not in user.email:
# Return None so that Firebase Auth rejects the account creation.
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
message="Unauthorized email",
)
برنامهتان باید خطا را شناسایی کند و برایناساس آن را مدیریت کند. برای مثال:
جاوا اسکریپت
import { getAuth, createUserWithEmailAndPassword } from 'firebase/auth';
// Blocking functions can also be triggered in a multi-tenant context before user creation.
// firebase.auth().tenantId = 'tenant-id-1';
const auth = getAuth();
try {
const result = await createUserWithEmailAndPassword(auth)
const idTokenResult = await result.user.getIdTokenResult();
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 ذخیره شده است و به کارخواه برگردانده میشود اصلاح کنید.
برای اصلاح کاربر، شیئی را از گرداننده رویداد خود برگردانید که حاوی فیلدهای موردنظر برای اصلاح باشد. میتوانید فیلدهای زیر را اصلاح کنید:
displayNamedisabledemailVerifiedphotoURLcustomClaims-
sessionClaims(فقطbeforeUserSignedIn)
بهاستثنای sessionClaims، همه فیلدهای اصلاحشده در پایگاه داده Firebase Authentication ذخیره میشوند، یعنی در کد پاسخ گنجانده میشوند و بین جلسههای کاربر باقی میمانند.
مثال زیر نشان میدهد که چگونه نام نمایشی پیشفرض را تنظیم کنید:
Node.js
export const beforecreated = beforeUserCreated((event) => {
return {
// If no display name is provided, set it to "Guest".
displayName: event.data.displayName || 'Guest'
};
});
پایتون
@identity_fn.before_user_created()
def setdefaultname(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
return identity_fn.BeforeCreateResponse(
# If no display name is provided, set it to "Guest".
display_name=event.data.display_name if event.data.display_name is not None else "Guest"
)
اگر یک گرداننده رویداد را برای هر دو beforeUserCreated و beforeUserSignedIn ثبت کنید،
توجه داشته باشید که beforeUserSignedIn پساز beforeUserCreated اجرا میشود. فیلدهای کاربر بهروزشده در
beforeUserCreated در beforeUserSignedIn قابلمشاهده است. اگر فیلدی غیراز
sessionClaims را در هر دو کنترلکننده رویداد تنظیم کنید، مقدار تنظیمشده در beforeUserSignedIn
روی مقدار تنظیمشده در beforeUserCreated بازنویسی میشود. فقط برای sessionClaims، آنها به ادعاهای توکن جلسه فعلی منتشر میشوند، اما در پایگاه داده ذخیره یا نگهداری نمیشوند.
برای مثال، اگر هرگونه sessionClaims تنظیم شده باشد، beforeUserSignedIn آنها را با هرگونه ادعای beforeUserCreated برمیگرداند و ادغام میشوند. وقتی ادغام میشوند، اگر
کلید sessionClaims با کلیدی در customClaims مطابقت داشته باشد،
customClaims منطبق در ادعاهای کد با کلید sessionClaims
رونویسی خواهد شد. بااینحال، کلید customClaims رونویسیشده همچنان در پایگاه داده برای درخواستهای آتی باقی خواهد ماند.
اعتبارنامهها و دادههای OAuth پشتیبانیشده
میتوانید اطلاعات کاربری و دادههای OAuth را از ارائهدهندگان هویت مختلف به توابع مسدودکننده ارسال کنید. جدول زیر نشان میدهد چه اطلاعات کاربری و دادههایی برای هر ارائهدهنده هویت پشتیبانی میشود:
| ارائهدهنده هویت | کد شناسه | کد دسترسی | زمان انقضا | رمز کد | ژتون بازآوری | ادعاهای ورود به سیستم |
|---|---|---|---|---|---|---|
| بله | بله | بله | نه | بله | نه | |
| فیسبوک | نه | بله | بله | نه | نه | نه |
| نه | بله | نه | بله | نه | نه | |
| GitHub | نه | بله | نه | نه | نه | نه |
| Microsoft | بله | بله | بله | نه | بله | نه |
| نه | بله | بله | نه | نه | نه | |
| Yahoo | بله | بله | بله | نه | بله | نه |
| Apple | بله | بله | بله | نه | بله | نه |
| SAML | نه | نه | نه | نه | نه | بله |
| OIDC | بله | بله | بله | نه | بله | بله |
کدهای OAuth
برای استفاده از کد شناسه، کد دسترسی، یا کد بازآوری در تابع مسدودسازی، باید ابتدا چارگوش انتخاب را در صفحه توابع مسدودسازی در کنسول 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=offlineprompt=consent، اگر کاربر قبلاً رضایت داده باشد و هیچ دامنه جدیدی درخواست نشده باشد
مثال:
import { getAuth, signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
const auth = getAuth();
const provider = new GoogleAuthProvider();
provider.setCustomParameters({
'access_type': 'offline',
'prompt': 'consent'
});
signInWithPopup(auth, provider);
درباره ژتونهای بازآوری Google بیشتر بدانید.
فیسبوک
وقتی کاربری با Facebook به سیستم وارد میشود، اطلاعات کاربری زیر ارسال میشود:
- کد دسترسی: کد دسترسیای برگردانده میشود که میتوان آن را با کد دسترسی دیگری مبادله کرد. درباره انواع مختلف کدهای دسترسی پشتیبانیشده توسط Facebook و نحوه مبادله آنها با کدهای با عمر طولانی بیشتر بدانید.
GitHub
وقتی کاربری با GitHub به سیستم وارد میشود، اعتبارنامه زیر ارسال خواهد شد:
- کد دسترسی: منقضی نمیشود مگراینکه لغو شود.
Microsoft
وقتی کاربری با Microsoft به سیستم وارد میشود، اعتبارنامههای زیر ارسال خواهد شد:
- شناسه دادهواحد
- کد دسترسی
- ژتون بازآوری: اگر
offline_accessscope انتخاب شده باشد، به تابع مسدودسازی ارسال میشود.
مثال:
import { getAuth, signInWithPopup, OAuthProvider } from 'firebase/auth';
const auth = getAuth();
const provider = new OAuthProvider('microsoft.com');
provider.addScope('offline_access');
signInWithPopup(auth, provider);
Yahoo
وقتی کاربری با Yahoo به سیستم وارد میشود، اطلاعات اعتباری زیر بدون هیچگونه پارامتر یا دامنه سفارشی ارسال میشود:
- شناسه دادهواحد
- کد دسترسی
- ژتون بازآوری
وقتی کاربر با LinkedIn به سیستم وارد میشود، اطلاعات کاربری زیر ارسال خواهد شد:
- کد دسترسی
Apple
وقتی کاربری با Apple به سیستم وارد میشود، اطلاعات اعتباری زیر بدون هیچگونه پارامتر یا دامنه سفارشی ارسال میشود:
- شناسه دادهواحد
- کد دسترسی
- ژتون بازآوری
سناریوهای رایج
مثالهای زیر برخیاز موارد استفاده رایج برای توابع مسدودسازی را نشان میدهند:
فقط ثبتنام از دامنهای خاص مجاز است
مثال زیر نشان میدهد چگونه میتوانید از ثبتنام کاربرانی که عضو دامنه
example.com نیستند در برنامهتان جلوگیری کنید:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
if (!user?.email?.includes('@example.com')) {
throw new HttpsError(
'invalid-argument', 'Unauthorized email');
}
});
پایتون
@identity_fn.before_user_created()
def validatenewuser(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
# User data passed in from the CloudEvent.
user = event.data
# Only users of a specific domain can sign up.
if user.email is None or "@example.com" not in user.email:
# Return None so that Firebase Auth rejects the account creation.
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
message="Unauthorized email",
)
مسدود کردن ثبتنام کاربران با ایمیلهای تأییدنشده
مثال زیر نشان میدهد چگونه از ثبتنام کاربران با ایمیلهای تأییدنشده در برنامهتان جلوگیری کنید:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
if (user.email && !user.emailVerified) {
throw new HttpsError(
'invalid-argument', 'Unverified email');
}
});
پایتون
@identity_fn.before_user_created()
def requireverified(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
if event.data.email is not None and not event.data.email_verified:
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
message="You must register using a trusted provider.",
)
درنظر گرفتن برخی ایمیلهای ارائهدهنده هویت بهعنوان درستیسنجیشده
مثال زیر نشان میدهد که چگونه ایمیلهای کاربر از ارائهدهندگان هویت خاص را بهعنوان تأییدشده درنظر بگیرید:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
if (user.email && !user.emailVerified && event.eventType.includes(':facebook.com')) {
return {
emailVerified: true,
};
}
});
پایتون
@identity_fn.before_user_created()
def markverified(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
if event.data.email is not None and "@facebook.com" in event.data.email:
return identity_fn.BeforeSignInResponse(email_verified=True)
مسدود کردن ورود به سیستم از نشانیهای IP خاص
مثال زیر نشان میدهد که چگونه ورود به سیستم را از محدودههای نشانی IP خاص مسدود کنید:
Node.js
export const beforesignedin = beforeUserSignedIn((event) => {
if (isSuspiciousIpAddress(event.ipAddress)) {
throw new HttpsError(
'permission-denied', 'Unauthorized access!');
}
});
پایتون
@identity_fn.before_user_signed_in()
def ipban(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeSignInResponse | None:
if is_suspicious(event.ip_address):
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.PERMISSION_DENIED, message="IP banned."
)
تنظیم ادعاهای سفارشی و جلسه
مثال زیر نشان میدهد که چگونه ادعاهای سفارشی و جلسه را تنظیم کنید:
Node.js
export const beforecreated = beforeUserCreated((event) => {
if (event.credential &&
event.credential.claims &&
event.credential.providerId === "saml.my-provider-id") {
return {
// Employee ID does not change so save in persistent claims (stored in
// Auth DB).
customClaims: {
eid: event.credential.claims.employeeid,
},
};
}
});
export const beforesignin = beforeUserSignedIn((event) => {
if (event.credential &&
event.credential.claims &&
event.credential.providerId === "saml.my-provider-id") {
return {
// Copy role and groups to token claims. These will not be persisted.
sessionClaims: {
role: event.credential.claims.role,
groups: event.credential.claims.groups,
},
};
}
});
پایتون
@identity_fn.before_user_created()
def setemployeeid(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
if (
event.credential is not None
and event.credential.claims is not None
and event.credential.provider_id == "saml.my-provider-id"
):
return identity_fn.BeforeCreateResponse(
custom_claims={"eid": event.credential.claims["employeeid"]}
)
@identity_fn.before_user_signed_in()
def copyclaimstosession(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeSignInResponse | None:
if (
event.credential is not None
and event.credential.claims is not None
and event.credential.provider_id == "saml.my-provider-id"
):
return identity_fn.BeforeSignInResponse(
session_claims={
"role": event.credential.claims["role"],
"groups": event.credential.claims["groups"],
}
)
ردیابی نشانیهای IP برای پایش فعالیتهای مشکوک
با ردیابی نشانی IP که کاربر از آن به سیستم وارد میشود و مقایسه آن با نشانی IP در درخواستهای بعدی، میتوانید از سرقت کد جلوگیری کنید. اگر درخواست مشکوک بهنظر میرسد (برای مثال، IPها از مناطق جغرافیایی مختلفی هستند)، میتوانید از کاربر بخواهید دوباره به سیستم وارد شود.
از ادعاهای جلسه برای ردیابی نشانی IP که کاربر با آن به سیستم وارد میشود استفاده کنید:
Node.js
export const beforesignedin = beforeUserSignedIn((event) => { return { sessionClaims: { signInIpAddress: event.ipAddress, }, }; });پایتون
@identity_fn.before_user_signed_in() def logip( event: identity_fn.AuthBlockingEvent, ) -> identity_fn.BeforeSignInResponse | None: return identity_fn.BeforeSignInResponse(session_claims={"signInIpAddress": event.ip_address})وقتی کاربری تلاش میکند به منابعی دسترسی پیدا کند که نیاز به اصالتسنجی با 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!' }) }); } }); });پایتون
from firebase_admin import auth, initialize_app import flask initialize_app() flask_app = flask.Flask(__name__) @flask_app.post() def get_restricted_data(req: flask.Request): # Get the ID token passed. id_token = req.json().get("idToken") # Verify the ID token, check if revoked, and decode its payload. try: claims = auth.verify_id_token(id_token, check_revoked=True) except: return flask.Response(status=500) # Get request IP address. request_ip = req.remote_addr # Get sign-in IP address. signin_ip = 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 is_suspicious_change(signin_ip, request_ip): # Suspicious IP address change. Require re-authentication. # You can also revoke all user sessions by calling: # auth.revoke_refresh_tokens(claims["sub"]) return flask.Response(status=401, response="Unauthorized access. Sign in again!") else: # Access is valid. Try to return data. return data_from_claims(claims)
درحال غربال کردن عکسهای کاربر
مثال زیر نحوه پاکسازی عکسهای نمایه کاربران را نشان میدهد:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
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,
};
}
});
});
پایتون
@identity_fn.before_user_created()
def sanitizeprofilephoto(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
if event.data.photo_url is not None:
score = analyze_photo_with_ml(event.data.photo_url)
if score > THRESHOLD:
return identity_fn.BeforeCreateResponse(photo_url=PLACEHOLDER_URL)
برای کسب اطلاعات بیشتر درباره نحوه شناسایی و پاکسازی تصاویر، به اسناد Cloud Vision مراجعه کنید.
دسترسی به اعتبارنامههای OAuth ارائهدهنده هویت کاربر
مثال زیر نشان میدهد که چگونه یک ژتون بازآوری برای کاربری که با Google به سیستم وارد شده است دریافت کنید و از آن برای فراخوانی Google Calendar APIs استفاده کنید. ژتون بازآوری برای دسترسی آفلاین ذخیره میشود.
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
);
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
if (event.credential &&
event.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,
event.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:
// event.additionalUserInfo.profile.granted_scopes (space joined list of scopes).
// Set access token/refresh token.
oAuth2Client.setCredentials({
access_token: event.credential.accessToken,
refresh_token: event.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();
});
});
})
}
});
پایتون
@identity_fn.before_user_created()
def savegoogletoken(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
"""During sign-up, save the Google OAuth2 access token and queue up a task
to schedule an onboarding session on the user's Google Calendar.
You will only get an access token if you enabled it in your project's blocking
functions settings in the Firebase console:
https://console.firebase.google.com/project/_/authentication/settings
"""
if event.credential is not None and event.credential.provider_id == "google.com":
print(f"Signed in with {event.credential.provider_id}. Saving access token.")
firestore_client: google.cloud.firestore.Client = firestore.client()
doc_ref = firestore_client.collection("user_info").document(event.data.uid)
doc_ref.set({"calendar_access_token": event.credential.access_token}, merge=True)
tasks_client = google.cloud.tasks_v2.CloudTasksClient()
task_queue = tasks_client.queue_path(
params.PROJECT_ID.value, options.SupportedRegion.US_CENTRAL1.value, "scheduleonboarding"
)
target_uri = get_function_url("scheduleonboarding")
calendar_task = google.cloud.tasks_v2.Task(
http_request={
"http_method": google.cloud.tasks_v2.HttpMethod.POST,
"url": target_uri,
"headers": {"Content-type": "application/json"},
"body": json.dumps({"data": {"uid": event.data.uid}}).encode(),
},
schedule_time=datetime.now() + timedelta(minutes=1),
)
tasks_client.create_task(parent=task_queue, task=calendar_task)
لغو کردن حکم reCAPTCHA Enterprise برای عملیات کاربر
مثال زیر نشان میدهد که چگونه میتوان حکم reCAPTCHA Enterprise را برای جریانهای کاربر پشتیبانیشده لغو کرد.
برای کسب اطلاعات بیشتر درباره ادغام کردن reCAPTCHA Enterprise با «اصالتسنجی Firebase»، به فعال کردن reCAPTCHA Enterprise مراجعه کنید.
از توابع مسدودسازی میتوان برای مجاز کردن یا مسدود کردن جریانها براساس عوامل سفارشی استفاده کرد و درنتیجه نتیجه ارائهشده توسط reCAPTCHA Enterprise را لغو کرد.
Node.js
const { beforeSmsSent } = require("firebase-functions/v2/identity");
exports.beforesmssentv2 = beforeSmsSent((event) => {
if (
event.smsType === "SIGN_IN_OR_SIGN_UP" &&
event.additionalUserInfo.phoneNumber.includes('+91')
) {
return {
recaptchaActionOverride: "ALLOW",
};
}
// Allow users to sign in with recaptcha score greater than 0.5
if (event.additionalUserInfo.recaptchaScore > 0.5) {
return {
recaptchaActionOverride: 'ALLOW',
};
}
// Block all others.
return {
recaptchaActionOverride: 'BLOCK',
}
});