Функции блокировки позволяют выполнять собственный код, который изменяет результат регистрации или входа пользователя в ваше приложение. Например, вы можете запретить пользователю проходить аутентификацию, если он не соответствует определенным критериям, или обновить информацию пользователя перед возвратом ее в клиентское приложение.
Прежде чем начать
Чтобы использовать функции блокировки, вам необходимо обновить проект Firebase до Firebase Authentication with Identity Platform . Если вы еще не обновились, сделайте это в первую очередь.
Понимание функций блокировки
Вы можете прописать функции блокировки для этих событий:
Перед созданием пользователя : срабатывает перед сохранением нового пользователя в базе данных Firebase Authentication и перед возвратом токена в ваше клиентское приложение.
Прежде чем пользователь войдет в систему : срабатывает после проверки учетных данных пользователя, но до того, как Firebase Authentication вернет токен идентификатора вашему клиентскому приложению. Если ваше приложение использует многофакторную аутентификацию, функция срабатывает после того, как пользователь подтвердит свой второй фактор. Обратите внимание, что создание нового пользователя также запускает оба этих события.
Перед отправкой электронного письма (только Node.js) : срабатывает перед отправкой электронного письма (например,
электронное письмо для входа или сброса пароля) отправляется пользователю.Перед отправкой SMS-сообщения (только Node.js) : срабатывает перед отправкой SMS-сообщения пользователю, в таких случаях, как многофакторная аутентификация.
При использовании функций блокировки имейте в виду следующее:
Ваша функция должна ответить в течение 7 секунд. Через 7 секунд Firebase Authentication возвращает ошибку, и операция клиента завершается с ошибкой.
Коды ответов HTTP, отличные от
200
передаются вашим клиентским приложениям. Убедитесь, что ваш клиентский код обрабатывает любые ошибки, которые может вернуть ваша функция.Функции применяются ко всем пользователям вашего проекта, включая всех, содержащихся в клиенте . Firebase Authentication предоставляет информацию о пользователях вашей функции, включая всех арендаторов, которым они принадлежат, чтобы вы могли отреагировать соответствующим образом.
Привязка другого поставщика удостоверений к учетной записи повторно запускает все зарегистрированные функции
beforeUserSignedIn
.Анонимная и пользовательская аутентификация не активируют функции блокировки.
Разверните функцию блокировки
Чтобы вставить свой собственный код в потоки аутентификации пользователей, разверните функции блокировки. После развертывания функций блокировки ваш пользовательский код должен успешно завершиться для успешной аутентификации и создания пользователя.
Вы развертываете функцию блокировки так же, как и любую другую функцию. (подробности см. на странице « Начало работы Cloud Functions ). В итоге:
Напишите функцию, которая обрабатывает целевое событие.
Например, для начала вы можете добавить в исходный код неактивную функцию, подобную следующей:
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 | Язык приложения. Вы можете установить языковой стандарт с помощью клиентского 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
в свою функцию. Например:
import { HttpsError } from "firebase-functions/v2/identity";
throw new HttpsError('invalid-argument');
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT)
Вы также можете указать собственное сообщение об ошибке:
throw new HttpsError('permission-denied', 'Unauthorized request origin!');
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.PERMISSION_DENIED,
message="Unauthorized request origin!"
)
В следующем примере показано, как заблокировать регистрацию в вашем приложении пользователей, которые не входят в определенный домен:
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 упаковывает ошибку и возвращает ее клиенту как внутреннюю ошибку. Например:
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 и возвращается клиенту.
Чтобы изменить пользователя, верните объект из обработчика событий, содержащий поля, которые нужно изменить. Вы можете изменить следующие поля:
-
displayName
-
disabled
-
emailVerified
-
photoUrl
-
customClaims
-
sessionClaims
(толькоbeforeUserSignedIn
)
За исключением sessionClaims
, все измененные поля сохраняются в базе данных Firebase Authentication , что означает, что они включаются в токен ответа и сохраняются между сеансами пользователя.
В следующем примере показано, как установить отображаемое имя по умолчанию:
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 | Нет | Да | Нет | Нет | Нет | Нет |
Майкрософт | Да | Да | Да | Нет | Да | Нет |
Нет | Да | Да | Нет | Нет | Нет | |
Yahoo | Да | Да | Да | Нет | Да | Нет |
Яблоко | Да | Да | Да | Нет | Да | Нет |
SAML | Нет | Нет | Нет | Нет | Нет | Да |
ОИДК | Да | Да | Да | Нет | Да | Да |
Токены 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=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, ему передаются следующие учетные данные:
- идентификационный токен
- Токен доступа
- Токен обновления : передается функции блокировки, если выбрана область
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, следующие учетные данные будут переданы без каких-либо настраиваемых параметров или областей:
- идентификационный токен
- Токен доступа
- Обновить токен
Распространенные сценарии
Следующие примеры демонстрируют некоторые распространенные случаи использования функций блокировки:
Разрешение регистрации только с определенного домена
В следующем примере показано, как запретить пользователям, не являющимся частью домена example.com
регистрироваться в вашем приложении:
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",
)
Блокировка регистрации пользователей с непроверенным адресом электронной почты
В следующем примере показано, как запретить пользователям с непроверенными адресами электронной почты регистрироваться в вашем приложении:
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.")
Считать определенные электронные письма поставщика удостоверений подтвержденными
В следующем примере показано, как считать электронные письма пользователей от определенных поставщиков удостоверений проверенными:
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-адресов:
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.")
Установка пользовательских и сеансовых утверждений
В следующем примере показано, как установить пользовательские утверждения и утверждения сеанса:
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-адреса, с помощью которого пользователь входит в систему:
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-адресом, используемым для входа:
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)
Проверка фотографий пользователей
В следующем примере показано, как очистить фотографии профиля пользователей:
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, и использовать его для вызова API Календаря Google. Токен обновления сохраняется для автономного доступа.
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,
"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», чтобы узнать больше об интеграции reCAPTCHA Enterprise с аутентификацией Firebase.
Функции блокировки можно использовать для разрешения или блокировки потоков на основе пользовательских факторов, тем самым переопределяя результат, предоставляемый reCAPTCHA Enterprise.
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',
}
});