Les fonctions de blocage vous permettent d'exécuter un code personnalisé qui modifie le résultat d'un utilisateur qui s'enregistre ou se connecte à votre application. Par exemple, vous pouvez empêcher un utilisateur de s'authentifier s'il ne répond pas à certains critères ou mettre à jour les informations d'un utilisateur avant de le renvoyer à votre application cliente.
Avant de commencer
Pour utiliser des fonctions bloquantes, vous devez mettre à niveau votre projet Firebase vers Firebase Authentication with Identity Platform. Si vous ne l'avez pas déjà fait, effectuez d'abord cette mise à niveau.
Comprendre les fonctions de blocage
Vous pouvez enregistrer des fonctions de blocage pour les événements suivants:
Avant la création de l'utilisateur: se déclenche avant qu'un nouvel utilisateur ne soit enregistré dans la base de données Firebase Authentication et avant qu'un jeton ne soit renvoyé à votre application cliente.
Avant que l'utilisateur ne se connecte: se déclenche après la validation des identifiants d'un utilisateur, mais avant que Firebase Authentication ne renvoie un jeton d'ID à votre application cliente. Si votre application utilise l'authentification multifacteur, la fonction se déclenche une fois que l'utilisateur a validé son second facteur. Notez que la création d'un utilisateur déclenche également ces deux événements.
Avant l'envoi d'un e-mail (Node.js uniquement): se déclenche avant l'envoi d'un e-mail (par exemple,un e-mail de connexion ou de réinitialisation de mot de passe) à un utilisateur.
Avant l'envoi d'un message SMS (Node.js uniquement): se déclenche avant l'envoi d'un message SMS à un utilisateur, par exemple pour l'authentification multifacteur.
Tenez compte des points suivants lorsque vous utilisez des fonctions de blocage :
Votre fonction doit répondre dans un délai de sept secondes. Au bout de sept secondes, Firebase Authentication renvoie une erreur, et l'opération client échoue.
Les codes de réponse HTTP autres que
200
sont transmis à vos applications clientes. Assurez-vous que le code client gère toutes les erreurs que votre fonction peut renvoyer.Les fonctions s'appliquent à tous les utilisateurs de votre projet, y compris les éléments contenus dans un locataire. Firebase Authentication fournit des informations sur les utilisateurs de votre fonction, y compris sur les locataires auxquels ils appartiennent. Vous pouvez ainsi répondre en conséquence.
Associer un autre fournisseur d'identité à un compte déclenche à nouveau les fonctions
beforeUserSignedIn
enregistrées.L'authentification anonyme et personnalisée ne déclenche pas de fonctions de blocage.
Déployer une fonction de blocage
Pour insérer votre code personnalisé dans les flux d'authentification des utilisateurs, déployez des fonctions de blocage. Une fois vos fonctions de blocage déployées, votre code personnalisé doit s'exécuter correctement pour que l'authentification et la création d'utilisateurs soient effectuées.
Vous déployez une fonction bloquante de la même manière que n'importe quelle fonction. (pour en savoir plus, consultez la page Cloud Functions Premiers pas). En résumé :
Écrivez une fonction qui gère l'événement ciblé.
Par exemple, pour commencer, vous pouvez ajouter une fonction sans opération comme celle-ci à votre source:
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
L'exemple ci-dessus a omis l'implémentation de la logique d'authentification personnalisée. Consultez les sections suivantes pour découvrir comment implémenter vos fonctions de blocage et les scénarios courants pour obtenir des exemples spécifiques.
Déployez vos fonctions à l'aide de la CLI Firebase:
firebase deploy --only functions
Vous devez redéployer vos fonctions chaque fois que vous les mettez à jour.
Obtenir des informations sur l'utilisateur et le contexte
Les événements de blocage fournissent un objet AuthBlockingEvent
contenant des informations sur la connexion de l'utilisateur. Utilisez ces valeurs dans votre code pour déterminer si vous souhaitez autoriser une opération.
L'objet contient les propriétés suivantes:
Nom | Description | Exemple |
---|---|---|
locale |
Paramètres régionaux de l'application. Vous pouvez définir les paramètres régionaux à l'aide du SDK client ou en transmettant l'en-tête des paramètres régionaux dans l'API REST. | fr ou sv-SE |
ipAddress
| Adresse IP de l'appareil à partir duquel l'utilisateur final s'enregistre ou se connecte. | 114.14.200.1 |
userAgent
| User-agent qui déclenche la fonction de blocage. | Mozilla/5.0 (X11; Linux x86_64) |
eventId
| Identifiant unique de l'événement. | rWsyPtolplG2TBFoOkkgyg |
eventType
|
Type d'événement. Fournit des informations sur le nom de l'événement, tels que beforeSignIn ou beforeCreate , ainsi que sur la méthode de connexion associée utilisée, par exemple Google ou la messagerie/mot de passe.
|
providers/cloud.auth/eventTypes/user.beforeSignIn:password
|
authType
| Toujours USER . |
USER
|
resource
| Le projet ou le locataire Firebase Authentication. |
projects/project-id/tenants/tenant-id
|
timestamp
| Heure à laquelle l'événement a été déclenché, au format de chaîne RFC 3339. | Tue, 23 Jul 2019 21:10:57 GMT
|
additionalUserInfo
| Objet contenant des informations sur l'utilisateur. |
AdditionalUserInfo
|
credential
| Objet contenant des informations sur les identifiants de l'utilisateur. |
AuthCredential
|
Blocage de l'enregistrement ou de la connexion
Pour bloquer une tentative d'enregistrement ou de connexion, envoyez une commande HttpsError
dans votre fonction. Exemple :
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)
Vous pouvez également spécifier un message d'erreur personnalisé :
Node.js
throw new HttpsError('permission-denied', 'Unauthorized request origin!');
Python (bêta)
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.PERMISSION_DENIED,
message="Unauthorized request origin!"
)
L'exemple suivant montre comment empêcher les utilisateurs qui ne font pas partie d'un domaine spécifique de s'inscrire à votre application :
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")
Que vous utilisiez un message par défaut ou personnalisé, Cloud Functions encapsule l'erreur et la renvoie au client en tant qu'erreur interne. Exemple :
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")
Votre application doit détecter l'erreur et la traiter en conséquence. Exemple :
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.
}
}
Modifier un compte utilisateur
Plutôt que de bloquer une tentative d'enregistrement ou de connexion, vous pouvez autoriser l'opération à continuer, mais modifier l'objet User
enregistré dans la base de données Firebase Authentication et renvoyé au client.
Pour modifier un utilisateur, renvoyez un objet à partir de votre gestionnaire d'événements contenant les champs à modifier. Vous pouvez modifier les champs suivants :
displayName
disabled
emailVerified
photoUrl
customClaims
sessionClaims
(beforeUserSignedIn
uniquement)
À l'exception de sessionClaims
, tous les champs modifiés sont enregistrés dans la base de données Firebase Authentication, ce qui signifie qu'ils sont inclus dans le jeton de réponse et conservés entre les sessions utilisateur.
L'exemple suivant montre comment définir un nom à afficher par défaut :
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")
Si vous enregistrez un gestionnaire d'événements pour beforeUserCreated
et beforeUserSignedIn
, notez que beforeUserSignedIn
s'exécute après beforeUserCreated
. Les champs utilisateur mis à jour dans beforeUserCreated
sont visibles dans beforeUserSignedIn
. Si vous définissez un champ autre que sessionClaims
dans les deux gestionnaires d'événements, la valeur définie dans beforeUserSignedIn
écrase la valeur définie dans beforeUserCreated
. Pour sessionClaims
uniquement, ils sont transmis aux revendications de jetons de la session en cours, mais ne sont pas conservés ni stockés dans la base de données.
Par exemple, si un élément sessionClaims
est défini, beforeUserSignedIn
les renverra avec les revendications beforeUserCreated
, et celles-ci sont fusionnées. Lorsqu'une clé sessionClaims
correspond à une clé de customClaims
, la clé customClaims
correspondante est écrasée dans les revendications de jeton par le sessionClaims
. Cependant, la clé overwiten customClaims
sera conservée dans la base de données pour les futures requêtes.
Identifiants et données OAuth compatibles
Vous pouvez transmettre des identifiants et des données OAuth à des fonctions de blocage provenant de divers fournisseurs d'identité. Le tableau suivant indique les identifiants et les données compatibles avec chaque fournisseur d'identité :
Fournisseur d'identité | Jeton d'ID | Jeton d'accès | Date/Heure d'expiration | Code secret du jeton | Jeton d'actualisation | Revendications de connexion |
---|---|---|---|---|---|---|
Oui | Oui | Oui | Non | Oui | Non | |
Non | Oui | Oui | Non | Non | Non | |
Non | Oui | Non | Oui | Non | Non | |
GitHub | Non | Oui | Non | Non | Non | Non |
Microsoft | Oui | Oui | Oui | Non | Oui | Non |
Non | Oui | Oui | Non | Non | Non | |
Yahoo | Oui | Oui | Oui | Non | Oui | Non |
Apple | Oui | Oui | Oui | Non | Oui | Non |
SAML | Non | Non | Non | Non | Non | Oui |
OIDC | Oui | Oui | Oui | Non | Oui | Oui |
Jetons OAuth
Pour utiliser un jeton d'identification, un jeton d'accès ou un jeton d'actualisation dans une fonction de blocage, vous devez d'abord cocher la case sur la page Fonctions de blocage de la console Firebase.
Les jetons d'actualisation ne sont pas renvoyés par les fournisseurs d'identité lorsqu'ils se connectent directement avec des identifiants OAuth, tels qu'un jeton d'ID ou un jeton d'accès. Dans ce cas, les mêmes identifiants OAuth côté client seront transmis à la fonction de blocage.
Les sections suivantes décrivent chaque type de fournisseur d'identité, ainsi que les identifiants et les données compatibles.
Fournisseurs OIDC génériques
Lorsqu'un utilisateur se connecte avec un fournisseur OIDC générique, les identifiants suivants sont transmis :
- Jeton d'identification : fourni si le flux
id_token
est sélectionné. - Jeton d'accès : fourni si le flux de code est sélectionné. Notez que le flux de code n'est actuellement compatible qu'avec l'API REST.
- Jeton d'actualisation : fourni si le champ d'application
offline_access
est sélectionné.
Exemple :
const provider = new firebase.auth.OAuthProvider('oidc.my-provider');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);
Lorsqu'un utilisateur se connecte avec Google, les identifiants suivants sont transmis :
- Jeton d'ID
- Jeton d'accès
- Jeton d'actualisation : cet élément n'est fourni que si les paramètres personnalisés suivants sont demandés :
access_type=offline
prompt=consent
, si l'utilisateur a déjà donné l'autorisation et qu'aucun nouveau champ d'application n'a été demandé
Exemple :
import { getAuth, signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
const auth = getAuth();
const provider = new GoogleAuthProvider();
provider.setCustomParameters({
'access_type': 'offline',
'prompt': 'consent'
});
signInWithPopup(auth, provider);
En savoir plus sur les jetons d'actualisation Google.
Lorsqu'un utilisateur se connecte avec Facebook, les identifiants suivants sont transmis :
- Jeton d'accès : un jeton d'accès est renvoyé qui peut être échangé pour un autre jeton d'accès. Découvrez les différents types de jetons d'accès acceptés par Facebook et apprenez à les échanger contre des jetons de longue durée.
GitHub
Lorsqu'un utilisateur se connecte avec GitHub, les identifiants suivants sont transmis :
- Jeton d'accès : n'expire pas, sauf s'il est révoqué.
Microsoft
Lorsqu'un utilisateur se connecte avec Microsoft, les identifiants suivants sont transmis :
- Jeton d'ID
- Jeton d'accès
- Jeton d'actualisation : transmis à la fonction de blocage si le champ d'application
offline_access
est sélectionné.
Exemple :
import { getAuth, signInWithPopup, OAuthProvider } from 'firebase/auth';
const auth = getAuth();
const provider = new OAuthProvider('microsoft.com');
provider.addScope('offline_access');
signInWithPopup(auth, provider);
Yahoo
Lorsqu'un utilisateur se connecte avec Yahoo, les identifiants suivants sont transmis sans paramètre ni champ d'application personnalisés :
- Jeton d'ID
- Jeton d'accès
- Jeton d'actualisation
Lorsqu'un utilisateur se connecte avec LinkedIn, les identifiants suivants sont transmis :
- Jeton d'accès
Apple
Lorsqu'un utilisateur se connecte avec Apple, les identifiants suivants sont transmis sans paramètre ni champ d'application personnalisés :
- Jeton d'ID
- Jeton d'accès
- Jeton d'actualisation
Scénarios courants
Les exemples suivants illustrent certains cas d'utilisation courants des fonctions de blocage :
Autoriser uniquement l'enregistrement depuis un domaine spécifique
L'exemple suivant montre comment empêcher les utilisateurs qui ne font pas partie du domaine example.com
de s'enregistrer avec votre application :
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 (bêta)
@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",
)
Empêcher les utilisateurs dont l'adresse e-mail n'a pas été validée
L'exemple suivant montre comment empêcher les utilisateurs associés à des adresses e-mail non validées d'être enregistrés dans votre application :
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.")
Traiter certaines adresses e-mail du fournisseur d'identité comme validées
L'exemple suivant montre comment traiter les e-mails des utilisateurs de certains fournisseurs d'identité comme validés :
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)
Bloquer la connexion à partir de certaines adresses IP
L'exemple suivant explique comment bloquer la connexion à partir de certaines plages d'adresses 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.")
Définir des revendications personnalisées et de session
L'exemple suivant montre comment définir des revendications personnalisées et de session :
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"]
})
Suivre les adresses IP pour surveiller les activités suspectes
Vous pouvez éviter le vol de jetons en effectuant le suivi de l'adresse IP à laquelle l'utilisateur se connecte et en la comparant à l'adresse IP lors des requêtes suivantes. Si la requête semble suspecte (par exemple, si les adresses IP proviennent de différentes régions géographiques), vous pouvez demander à l'utilisateur de se reconnecter.
Utilisez les revendications de session pour suivre l'adresse IP avec laquelle l'utilisateur se connecte :
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})
Lorsqu'un utilisateur tente d'accéder à des ressources nécessitant une authentification avec Firebase Authentication, comparez l'adresse IP de la requête avec l'adresse IP utilisée pour se connecter:
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 (bêta)
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)
Filtrer les photos des utilisateurs
L'exemple suivant montre comment nettoyer les photos de profil des utilisateurs :
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)
Pour en savoir plus sur la détection et le nettoyage des images, consultez la documentation de Cloud Vision.
Accéder aux identifiants OAuth du fournisseur d'identité d'un utilisateur
L'exemple suivant montre comment obtenir un jeton d'actualisation pour un utilisateur connecté à Google et l'utiliser pour appeler les API Google Agenda. Le jeton d'actualisation est stocké pour un accès hors connexion.
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)
Forcer l'évaluation reCAPTCHA Enterprise pour l'opération de l'utilisateur
L'exemple suivant montre comment remplacer une évaluation reCAPTCHA Enterprise pour les flux utilisateur compatibles.
Consultez Activer reCAPTCHA Enterprise pour en savoir plus sur l'intégration de reCAPTCHA Enterprise à Firebase Authentication.
Les fonctions de blocage peuvent être utilisées pour autoriser ou bloquer des flux en fonction de facteurs personnalisés, ce qui remplace le résultat fourni par 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',
}
});