Блокирующие функции позволяют выполнять пользовательский код, изменяющий результат регистрации или входа пользователя в ваше приложение. Например, вы можете запретить пользователю аутентификацию, если он не соответствует определенным критериям, или обновить информацию о пользователе перед ее возвратом в ваше клиентское приложение.
Прежде чем начать
Для использования блокирующих функций необходимо обновить ваш проект Firebase до Firebase Authentication with Identity Platform . Если вы еще этого не сделали, выполните обновление в первую очередь.
Понимание блокирующих функций
Для этих событий можно зарегистрировать функции блокировки:
Перед созданием пользователя : срабатывает перед сохранением нового пользователя в базу данных Firebase Authentication и перед возвратом токена в ваше клиентское приложение.
Перед авторизацией пользователя : функция срабатывает после проверки учетных данных пользователя, но до того, как Firebase Authentication вернет токен ID вашему клиентскому приложению. Если ваше приложение использует многофакторную аутентификацию, функция срабатывает после того, как пользователь подтвердит свой второй фактор. Обратите внимание, что создание нового пользователя также запускает оба этих события.
Перед отправкой электронного письма (только для Node.js) : срабатывает перед отправкой электронного письма пользователю (например, письма для входа в систему или сброса пароля).
Перед отправкой SMS-сообщения (только для Node.js) : срабатывает перед отправкой SMS-сообщения пользователю, например, при многофакторной аутентификации.
При использовании блокирующих функций следует учитывать следующее:
Ваша функция должна ответить в течение 7 секунд. По истечении 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 CLI:
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 и возвращается клиенту.
Для изменения данных пользователя верните из обработчика событий объект, содержащий поля, которые необходимо изменить. Вы можете изменить следующие поля:
-
displayName -
disabled -
emailVerified -
photoUrl -
customClaims -
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'
};
});
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 | Да | Да | Да | Нет | Да | Нет |
| Нет | Да | Да | Нет | Нет | Нет | |
| Яху | Да | Да | Да | Нет | Да | Нет |
| Яблоко | Да | Да | Да | Нет | Да | Нет |
| SAML | Нет | Нет | Нет | Нет | Нет | Да |
| ОИДК | Да | Да | Да | Нет | Да | Да |
Токены OAuth
Чтобы использовать токен ID, токен доступа или токен обновления в блокирующей функции, необходимо сначала установить флажок на странице «Блокирующие функции» в консоли 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 передаются следующие учетные данные:
- ID токен
- токен доступа
- Токен обновления : Предоставляется только в том случае, если запрошены следующие пользовательские параметры:
-
access_type=offline -
prompt=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 будут переданы следующие учетные данные:
- ID токен
- токен доступа
- Токен обновления : передается в блокирующую функцию, если выбрана область действия
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 будут передаваться следующие учетные данные без каких-либо пользовательских параметров или областей действия:
- ID токен
- токен доступа
- Токен обновления
При входе пользователя через LinkedIn будут переданы следующие учетные данные:
- токен доступа
Яблоко
При входе пользователя в систему с помощью Apple будут переданы следующие учетные данные без каких-либо пользовательских параметров или областей действия:
- ID токен
- токен доступа
- Токен обновления
Типичные сценарии
Следующие примеры демонстрируют некоторые распространенные варианты использования блокирующих функций:
Регистрация разрешена только с определенного домена.
В следующем примере показано, как предотвратить регистрацию в вашем приложении пользователей, не являющихся пользователями домена 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, и использовать его для вызова 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
);
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,
"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» .
Функции блокировки позволяют разрешать или блокировать потоки на основе заданных параметров, тем самым отменяя результат, предоставляемый 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',
}
});