As funções de bloqueio permitem executar código personalizado que modifica o resultado do registro ou login de um usuário em seu aplicativo. Por exemplo, você pode impedir que um usuário se autentique se ele não atender a determinados critérios ou atualizar as informações de um usuário antes de devolvê-las ao seu aplicativo cliente.
Antes de você começar
Para usar funções de bloqueio, você deve atualizar seu projeto do Firebase para Firebase Authentication with Identity Platform. Se você ainda não atualizou, faça-o primeiro.
Compreendendo as funções de bloqueio
Você pode registrar funções de bloqueio para dois eventos:
Antes da criação do usuário : é acionado antes que um novo usuário seja salvo no banco de dados do Firebase Authentication e antes que um token seja retornado ao seu aplicativo cliente.
Antes de o usuário fazer login : é acionado depois que as credenciais de um usuário são verificadas, mas antes que o Firebase Authentication retorne um token de ID para seu aplicativo cliente. Se seu aplicativo usar autenticação multifator, a função será acionada depois que o usuário verificar o segundo fator. Observe que a criação de um novo usuário também aciona esses dois eventos.
Lembre-se do seguinte ao usar funções de bloqueio:
Sua função deve responder dentro de 7 segundos. Após sete segundos, o Firebase Authentication retorna um erro e a operação do cliente falha.
Códigos de resposta HTTP diferentes de
200
são passados para seus aplicativos cliente. Certifique-se de que seu código cliente lide com quaisquer erros que sua função possa retornar.As funções se aplicam a todos os usuários do seu projeto, incluindo aqueles contidos em um locatário . O Firebase Authentication fornece informações sobre os usuários da sua função, incluindo os locatários aos quais eles pertencem, para que você possa responder adequadamente.
Vincular outro provedor de identidade a uma conta reativa qualquer função
beforeUserSignedIn
registrada.A autenticação anônima e personalizada não aciona funções de bloqueio.
Implantar uma função de bloqueio
Para inserir seu código personalizado nos fluxos de autenticação do usuário, implante funções de bloqueio. Depois que suas funções de bloqueio forem implementadas, seu código personalizado deverá ser concluído com êxito para que a autenticação e a criação de usuário sejam bem-sucedidas.
Você implanta uma função de bloqueio da mesma forma que implanta qualquer função. (consulte a página de primeiros passos do Cloud Functions para obter detalhes). Resumindo:
Grave funções do Cloud que processam o evento
beforeUserCreated
, o eventobeforeUserSignedIn
ou ambos.Por exemplo, para começar, você pode adicionar as seguintes funções autônomas ao
index.js
:import {
beforeUserCreated,
beforeUserSignedIn,
} from "firebase-functions/v2/identity";
export const beforecreated = beforeUserCreated((event) => {
// TODO
return;
});
export const beforesignedin = beforeUserSignedIn((event) => {
// TODO
});@identity_fn.before_user_created()
def created_noop(event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None:
return
@identity_fn.before_user_signed_in()
def signedin_noop(event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeSignInResponse | None:
returnOs exemplos acima omitiram a implementação da lógica de autenticação personalizada. Consulte as seções a seguir para saber como implementar suas funções de bloqueio e cenários comuns para exemplos específicos.
Implante suas funções usando a CLI do Firebase:
firebase deploy --only functions
Você deve reimplantar suas funções sempre que atualizá-las.
Obtendo informações do usuário e do contexto
Os eventos beforeUserSignedIn
e beforeUserCreated
fornecem um objeto AuthBlockingEvent
que contém informações sobre o login do usuário. Use esses valores em seu código para determinar se uma operação deve continuar.
Os eventos de bloqueio fornecem um objeto que contém informações sobre o login do usuário. Use esses valores em seu código para determinar se uma operação deve continuar.
O objeto contém as seguintes propriedades:
Nome | Descrição | Exemplo |
---|---|---|
locale | A localidade do aplicativo. Você pode definir a localidade usando o SDK do cliente ou passando o cabeçalho da localidade na API REST. | fr ou sv-SE |
ipAddress | O endereço IP do dispositivo a partir do qual o usuário final está registrando ou fazendo login. | 114.14.200.1 |
userAgent | O agente do usuário que aciona a função de bloqueio. | Mozilla/5.0 (X11; Linux x86_64) |
eventId | O identificador exclusivo do evento. | rWsyPtolplG2TBFoOkkgyg |
eventType | O tipo de evento. Isso fornece informações sobre o nome do evento, como beforeSignIn ou beforeCreate , e o método de login associado usado, como Google ou email/senha. | providers/cloud.auth/eventTypes/user.beforeSignIn:password |
authType | Sempre USER . | USER |
resource | O projeto ou locatário do Firebase Authentication. | projects/ project-id /tenants/ tenant-id |
timestamp | A hora em que o evento foi acionado, formatado como uma string RFC 3339 . | Tue, 23 Jul 2019 21:10:57 GMT |
additionalUserInfo | Um objeto que contém informações sobre o usuário. | AdditionalUserInfo |
credential | Um objeto que contém informações sobre a credencial do usuário. | AuthCredential |
Bloqueando registro ou login
Para bloquear um registro ou tentativa de login, lance um HttpsError
em sua função. Por exemplo:
import { HttpsError } from "firebase-functions/v2/identity";
throw new HttpsError('invalid-argument');
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT)
Você também pode especificar uma mensagem de erro personalizada:
throw new HttpsError('permission-denied', 'Unauthorized request origin!');
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.PERMISSION_DENIED,
message="Unauthorized request origin!"
)
O exemplo a seguir mostra como impedir que usuários que não estejam em um domínio específico se registrem em seu aplicativo:
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")
Independentemente de você usar uma mensagem padrão ou personalizada, o Cloud Functions encapsula o erro e o retorna ao cliente como um erro interno. Por exemplo:
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")
Seu aplicativo deve detectar o erro e tratá-lo adequadamente. Por exemplo:
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.
}
}
Modificando um usuário
Em vez de bloquear uma tentativa de registro ou login, você pode permitir que a operação continue, mas modificar o objeto User
que é salvo no banco de dados do Firebase Authentication e retornado ao cliente.
Para modificar um usuário, retorne um objeto do seu manipulador de eventos contendo os campos a serem modificados. Você pode modificar os seguintes campos:
-
displayName
-
disabled
-
emailVerified
-
photoUrl
-
customClaims
-
sessionClaims
(apenasbeforeUserSignedIn
)
Com exceção de sessionClaims
, todos os campos modificados são salvos no banco de dados do Firebase Authentication, o que significa que são incluídos no token de resposta e persistem entre as sessões do usuário.
O exemplo a seguir mostra como definir um nome de exibição padrão:
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")
Se você registrar um manipulador de eventos para beforeUserCreated
e beforeUserSignedIn
, observe que beforeUserSignedIn
é executado após beforeUserCreated
. Os campos de usuário atualizados em beforeUserCreated
são visíveis em beforeUserSignedIn
. Se você definir um campo diferente de sessionClaims
em ambos os manipuladores de eventos, o valor definido em beforeUserSignedIn
substituirá o valor definido em beforeUserCreated
. Somente para sessionClaims
, eles são propagados para as declarações de token da sessão atual, mas não são persistidos ou armazenados no banco de dados.
Por exemplo, se quaisquer sessionClaims
forem definidas, beforeUserSignedIn
as retornará com quaisquer declarações beforeUserCreated
e elas serão mescladas. Quando eles forem mesclados, se uma chave sessionClaims
corresponder a uma chave em customClaims
, os customClaims
correspondentes serão substituídos nas declarações de token pela chave sessionClaims
. No entanto, a chave customClaims
ignorada ainda persistirá no banco de dados para solicitações futuras.
Credenciais e dados OAuth compatíveis
Você pode passar credenciais e dados do OAuth para funções de bloqueio de vários provedores de identidade. A tabela a seguir mostra quais credenciais e dados são compatíveis com cada provedor de identidade:
Provedor de identidade | Token de identificação | Token de acesso | Data de validade | Segredo do token | Atualizar token | Reivindicações de login |
---|---|---|---|---|---|---|
Sim | Sim | Sim | Não | Sim | Não | |
Não | Sim | Sim | Não | Não | Não | |
Não | Sim | Não | Sim | Não | Não | |
GitHub | Não | Sim | Não | Não | Não | Não |
Microsoft | Sim | Sim | Sim | Não | Sim | Não |
Não | Sim | Sim | Não | Não | Não | |
Yahoo | Sim | Sim | Sim | Não | Sim | Não |
Maçã | Sim | Sim | Sim | Não | Sim | Não |
SAML | Não | Não | Não | Não | Não | Sim |
OIDC | Sim | Sim | Sim | Não | Sim | Sim |
Tokens OAuth
Para usar um token de ID, token de acesso ou token de atualização em uma função de bloqueio, primeiro marque a caixa de seleção na página Funções de bloqueio do console do Firebase.
Os tokens de atualização não serão retornados por nenhum provedor de identidade ao fazer login diretamente com uma credencial OAuth, como um token de ID ou token de acesso. Nessa situação, a mesma credencial OAuth do lado do cliente será passada para a função de bloqueio.
As seções a seguir descrevem cada tipo de provedor de identidade e suas credenciais e dados suportados.
Provedores genéricos de OIDC
Quando um usuário entra com um provedor OIDC genérico, as seguintes credenciais serão passadas:
- Token de ID : fornecido se o fluxo
id_token
for selecionado. - Token de acesso : fornecido se o fluxo de código for selecionado. Observe que o fluxo de código só tem suporte atualmente por meio da API REST.
- Token de atualização : fornecido se o escopo
offline_access
for selecionado.
Exemplo:
const provider = new firebase.auth.OAuthProvider('oidc.my-provider');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);
Quando um usuário fizer login no Google, as seguintes credenciais serão transmitidas:
- Token de identificação
- Token de acesso
- Token de atualização : fornecido somente se os seguintes parâmetros personalizados forem solicitados:
-
access_type=offline
-
prompt=consent
, se o usuário consentiu anteriormente e nenhum novo escopo foi solicitado
-
Exemplo:
import { getAuth, signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
const auth = getAuth();
const provider = new GoogleAuthProvider();
provider.setCustomParameters({
'access_type': 'offline',
'prompt': 'consent'
});
signInWithPopup(auth, provider);
Saiba mais sobre os tokens de atualização do Google .
Quando um usuário entra no Facebook, a seguinte credencial será passada:
- Token de acesso : é retornado um token de acesso que pode ser trocado por outro token de acesso. Saiba mais sobre os diferentes tipos de tokens de acesso suportados pelo Facebook e como você pode trocá-los por tokens de longa duração .
GitHub
Quando um usuário fizer login no GitHub, a seguinte credencial será passada:
- Token de acesso : não expira a menos que seja revogado.
Microsoft
Quando um usuário entrar na Microsoft, as seguintes credenciais serão passadas:
- Token de identificação
- Token de acesso
- Token de atualização : passado para a função de bloqueio se o escopo
offline_access
for selecionado.
Exemplo:
import { getAuth, signInWithPopup, OAuthProvider } from 'firebase/auth';
const auth = getAuth();
const provider = new OAuthProvider('microsoft.com');
provider.addScope('offline_access');
signInWithPopup(auth, provider);
Yahoo
Quando um usuário faz login no Yahoo, as seguintes credenciais serão passadas sem quaisquer parâmetros ou escopos personalizados:
- Token de identificação
- Token de acesso
- Atualizar token
Quando um usuário entra no LinkedIn, a seguinte credencial será passada:
- Token de acesso
Maçã
Quando um usuário faz login na Apple, as seguintes credenciais serão transmitidas sem parâmetros ou escopos personalizados:
- Token de identificação
- Token de acesso
- Atualizar token
Cenários comuns
Os exemplos a seguir demonstram alguns casos de uso comuns para funções de bloqueio:
Permitindo apenas o registro de um domínio específico
O exemplo a seguir mostra como impedir que usuários que não fazem parte do domínio example.com
se registrem no seu aplicativo:
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",
)
Bloqueando o registro de usuários com e-mails não verificados
O exemplo a seguir mostra como evitar que usuários com e-mails não verificados se registrem no seu aplicativo:
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.")
Tratar determinados e-mails de provedores de identidade como verificados
O exemplo a seguir mostra como tratar e-mails de usuários de determinados provedores de identidade como verificados:
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)
Bloqueando login de determinados endereços IP
O exemplo a seguir mostra como bloquear a entrada de determinados intervalos de endereços 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.")
Configurando declarações personalizadas e de sessão
O exemplo a seguir mostra como definir declarações personalizadas e de sessão:
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"]
})
Rastreamento de endereços IP para monitorar atividades suspeitas
Você pode evitar o roubo de token rastreando o endereço IP a partir do qual um usuário faz login e comparando-o com o endereço IP nas solicitações subsequentes. Se a solicitação parecer suspeita — por exemplo, os IPs são de regiões geográficas diferentes — você pode pedir ao usuário para fazer login novamente.
Use declarações de sessão para rastrear o endereço IP com o qual o usuário faz login:
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})Quando um usuário tentar acessar recursos que exigem autenticação com o Firebase Authentication, compare o endereço IP na solicitação com o IP usado para fazer login:
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)
Triagem de fotos do usuário
O exemplo a seguir mostra como higienizar as fotos de perfil dos usuários:
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)
Para saber mais sobre como detectar e higienizar imagens, consulte a documentação do Cloud Vision .
Acessando as credenciais OAuth do provedor de identidade de um usuário
O exemplo a seguir demonstra como obter um token de atualização para um usuário que fez login no Google e usá-lo para chamar as APIs do Google Agenda. O token de atualização é armazenado para acesso offline.
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)
Substituir o veredicto do reCAPTCHA Enterprise para operação do usuário
O exemplo a seguir mostra como substituir um veredicto do reCAPTCHA Enterprise para fluxos de usuários compatíveis.
Consulte Ativar o reCAPTCHA Enterprise para saber mais sobre a integração do reCAPTCHA Enterprise com o Firebase Authentication.
As funções de bloqueio podem ser usadas para permitir ou bloquear fluxos com base em fatores personalizados, substituindo assim o resultado fornecido pelo reCAPTCHA Enterprise.
const {
beforeUserSignedIn,
} = require("firebase-functions/v2/identity");
exports const checkrecaptcha = beforeUserSignedIn(async (event) => {
const user = event.data;
// Allow users with a specific email domain to sign in regardless of their recaptcha score.
if (user.email && user.email.indexOf('@acme.com') !== -1) {
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: 'BLOCKED',
}
});