Функции блокировки позволяют выполнять пользовательский код, который изменяет результат регистрации или входа пользователя в ваше приложение. Например, вы можете запретить пользователю проходить аутентификацию, если он не соответствует определенным критериям, или обновить информацию о пользователе, прежде чем возвращать ее в клиентское приложение.
Подготовка
Чтобы использовать функции блокировки, необходимо перейти на тарифный план Firebase Authentication with Identity Platform. Если вы ещё не перешли на новую версию, сделайте это.
Как работают функции блокировки
Вы можете зарегистрировать блокирующие функции для следующих событий:
Перед созданием пользователя. Триггер срабатывает до того, как новый пользователь сохраняется в базе данных Firebase Authentication и до того, как токен возвращается в клиентское приложение.
Перед входом пользователя. Срабатывает после проверки учетных данных пользователя, но до того, как Firebase Authentication вернет токен идентификатора вашему клиентскому приложению. Если в приложении используется многофакторная аутентификация, функция срабатывает после того, как пользователь подтвердит второй фактор. Обратите внимание, что при создании нового пользователя также активируются оба этих события.
Перед отправкой электронного письма (только Node.js). Срабатывает перед отправкой пользователю электронного письма (например, для входа в систему или сброса пароля).
Перед отправкой SMS-сообщения (только Node.js). Срабатывает перед отправкой SMS-сообщения пользователю, например при многофакторной аутентификации.
При использовании функций блокировки учитывайте следующее:
Функция должна ответить в течение семи секунд. Через 7 секунд 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; });Python
@identity_fn.before_user_created() def created_noop( event: identity_fn.AuthBlockingEvent, ) -> identity_fn.BeforeCreateResponse | None: returnВ приведенном выше примере не показана реализация специальной логики аутентификации. В разделах ниже рассказывается, как реализовать функции блокировки, а в разделе Распространенные сценарии приведены примеры.
Разверните функции с помощью интерфейса командной строки Firebase:
firebase deploy --only functionsВам необходимо повторно развертывать свои функции каждый раз, когда вы их обновляете.
Получение информации о пользователе и контексте
События блокировки предоставляют объект AuthBlockingEvent, который содержит информацию о пользователе, выполняющем вход. Используйте эти значения в коде, чтобы определить, разрешать ли выполнение операции.
Объект содержит следующие свойства:
| Имя | Описание | Пример |
|---|---|---|
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. Пример:
Node.js
import { HttpsError } from "firebase-functions/v2/identity";
throw new HttpsError('invalid-argument');
Python
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT)
Вы также можете указать собственное сообщение об ошибке:
Node.js
throw new HttpsError('permission-denied', 'Unauthorized request origin!');
Python
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");
}
});
Python
# 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");
Python
# 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",
)
Приложение должно перехватывать ошибку и обрабатывать ее соответствующим образом. Пример:
JavaScript
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 и возвращается клиенту.
Чтобы изменить пользователя, верните из обработчика событий объект, содержащий поля, которые нужно изменить. Вы можете изменить следующие поля:
displayNamedisabledemailVerifiedphotoURLcustomClaimssessionClaims(только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'
};
});
Python
@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_access.
Пример:
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');
}
});
Python
@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');
}
});
Python
@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,
};
}
});
Python
@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!');
}
});
Python
@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,
},
};
}
});
Python
@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, }, }; });Python
@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!' }) }); } }); });Python
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,
};
}
});
});
Python
@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 Календаря 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
);
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();
});
});
})
}
});
Python
@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 Authentication…
Функции блокировки позволяют разрешать или блокировать процессы на основе пользовательских факторов, переопределяя результат, предоставленный 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',
}
});