Firebase Authentication um Blockierfunktionen erweitern


Mit Blockierfunktionen können Sie benutzerdefinierten Code ausführen, der das Ergebnis einer Nutzerregistrierung oder Anmeldung bei Ihrer Anwendung ändert. Sie können beispielsweise verhindern, dass ein Nutzer sich authentifizieren kann, wenn er bestimmte Kriterien nicht erfüllt, oder seine Informationen aktualisieren, bevor sie an die Clientanwendung zurückgegeben werden.

Hinweis

Wenn Sie Blockierungsfunktionen verwenden möchten, müssen Sie Ihr Firebase-Projekt auf Firebase Authentication with Identity Platform aktualisieren. Wenn Sie das Upgrade noch nicht durchgeführt haben, führen Sie es zuerst aus.

Informationen zu Blockierfunktionen

Sie können Blockierfunktionen für diese Ereignisse registrieren:

  • Vor dem Erstellen des Nutzers: Wird ausgelöst, bevor ein neuer Nutzer in der Firebase Authentication-Datenbank gespeichert wird und bevor ein Token an die Clientanwendung zurückgegeben wird.

  • Vor der Anmeldung des Nutzers: Wird ausgelöst, nachdem die Anmeldedaten eines Nutzers geprüft wurden, aber bevor Firebase Authentication ein ID-Token an Ihre Clientanwendung zurückgibt. Wenn Ihre Anwendung die Multi-Faktor-Authentifizierung verwendet, wird die Funktion ausgelöst, nachdem der Nutzer seinen zweiten Faktor überprüft hat. Beachten Sie, dass durch das Erstellen eines neuen Nutzers beide Ereignisse ausgelöst werden.

  • Vor dem Senden einer E-Mail (nur Node.js): Wird ausgelöst,bevor eine E-Mail (z. B. eine E-Mail zum Anmelden oder Zurücksetzen des Passworts) an einen Nutzer gesendet wird.

  • Vor dem Senden einer SMS-Nachricht (nur Node.js): Wird ausgelöst, bevor eine SMS an einen Nutzer gesendet wird, z. B. bei der Multi-Faktor-Authentifizierung.

Beachten Sie bei der Verwendung von Blockierfunktionen Folgendes:

  • Die Funktion muss innerhalb von 7 Sekunden antworten. Nach sieben Sekunden gibt Firebase Authentication einen Fehler zurück und der Clientvorgang schlägt fehl.

  • Andere HTTP-Antwortcodes als 200 werden an Ihre Clientanwendungen weitergeleitet. Achten Sie darauf, dass der Clientcode alle Fehler verarbeitet, die von der Funktion zurückgegeben werden.

  • Funktionen gelten für alle Nutzer in Ihrem Projekt, einschließlich der in einem Mandanten enthaltenen Nutzer. Firebase Authentication stellt der Funktion Informationen über Nutzer bereit, einschließlich aller Mandanten, zu denen sie gehören, damit Sie entsprechend reagieren können.

  • Durch die Verknüpfung eines anderen Identitätsanbieters mit einem Konto werden alle registrierten beforeUserSignedIn-Funktionen noch einmal ausgelöst.

  • Bei der anonymen und benutzerdefinierten Authentifizierung werden keine Blockierfunktionen ausgelöst.

Blockierfunktion bereitstellen

Wenn Sie Ihren benutzerdefinierten Code in die Authentifizierungsabläufe der Nutzer einfügen möchten, müssen Sie Blockierfunktionen bereitstellen. Nachdem Ihre Blockierfunktionen bereitgestellt wurden, muss Ihr benutzerdefinierter Code erfolgreich abgeschlossen werden, damit die Authentifizierung und Nutzererstellung erfolgreich abgeschlossen werden können.

Sie stellen eine Blockierungsfunktion auf die gleiche Weise bereit wie jede andere Funktion. Weitere Informationen finden Sie auf der Seite Cloud Functions Einstieg. Zusammenfassung:

  1. Schreiben Sie eine Funktion, die das gewünschte Ereignis verarbeitet.

    Zuerst können Sie Ihrer Quelle beispielsweise eine No-Op-Funktion wie die folgende hinzufügen:

    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
    

    Im obigen Beispiel wurde die Implementierung der benutzerdefinierten Authentifizierungslogik weggelassen. In den folgenden Abschnitten erfahren Sie, wie Sie Blockierfunktionen implementieren. Gängige Szenarien enthält konkrete Beispiele.

  2. Funktionen mit der Firebase-Befehlszeile bereitstellen:

    firebase deploy --only functions
    

    Sie müssen Ihre Funktionen jedes Mal neu bereitstellen, wenn Sie sie aktualisieren.

Nutzer- und Kontextinformationen abrufen

Blockierungsereignisse stellen ein AuthBlockingEvent-Objekt bereit, das Informationen zum Nutzer enthält, der sich anmeldet. Verwenden Sie diese Werte in Ihrem Code, um festzustellen, ob ein Vorgang fortgesetzt werden soll.

Das Objekt enthält die folgenden Eigenschaften:

Name Beschreibung Beispiel
locale Die Sprache der Anwendung. Sie können das Gebietsschema mit dem Client SDK festlegen oder den Sprachheader in der REST API übergeben. fr oder sv-SE
ipAddress Die IP-Adresse des Geräts, über das sich der Endnutzer registriert oder anmeldet. 114.14.200.1
userAgent Der User-Agent, der die Blockierfunktion auslöst. Mozilla/5.0 (X11; Linux x86_64)
eventId Die eindeutige Kennung des Ereignisses. rWsyPtolplG2TBFoOkkgyg
eventType Der Ereignistyp. Es enthält Informationen zum Ereignisnamen, z. B. beforeSignIn oder beforeCreate, und die zugehörige Anmeldemethode, z. B. Google oder E-Mail-Adresse/Passwort. providers/cloud.auth/eventTypes/user.beforeSignIn:password
authType Immer USER. USER
resource Das Firebase Authentication-Projekt oder der Firebase Authentication-Mandant. projects/project-id/tenants/tenant-id
timestamp Die Zeit, zu der das Ereignis ausgelöst wurde, formatiert als RFC 3339-String. Tue, 23 Jul 2019 21:10:57 GMT
additionalUserInfo Ein Objekt mit Informationen zum Nutzer. AdditionalUserInfo
credential Ein Objekt mit Informationen zu den Anmeldedaten des Nutzers. AuthCredential

Registrierung oder Anmeldung blockieren

Wenn Sie einen Registrierungs- oder Anmeldeversuch blockieren möchten, geben Sie in der Funktionen den Fehler HttpsError aus. Beispiel:

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)

Sie können auch eine benutzerdefinierte Fehlermeldung angeben:

Node.js

throw new HttpsError('permission-denied', 'Unauthorized request origin!');

Python (Vorabversion)

raise https_fn.HttpsError(
    code=https_fn.FunctionsErrorCode.PERMISSION_DENIED,
    message="Unauthorized request origin!"
)

Das folgende Beispiel zeigt, wie Sie Nutzer, die nicht Mitglieder innerhalb einer bestimmten Domain sind, daran hindern, sich bei Ihrer Anwendung anzumelden:

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")

Unabhängig davon, ob Sie eine Standard- oder benutzerdefinierte Nachricht verwenden, gibt Cloud Functions den Fehler als internen Fehler an den Client zurück. Beispiel:

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")

Ihre Anwendung erkennt den Fehler und reagiert entsprechend. Beispiel:

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.
    }
}

Nutzer ändern

Anstatt einen Registrierungs- oder Anmeldeversuch zu blockieren, können Sie den Vorgang fortsetzen, aber das User-Objekt ändern, das in der Datenbank von Firebase Authentication gespeichert ist und an den Client zurückgegeben wird.

Um einen Nutzer zu ändern, geben Sie ein Objekt aus Ihrem Ereignis-Handler zurück, der die zu ändernden Felder enthält. Sie können die folgenden Felder ändern:

  • displayName
  • disabled
  • emailVerified
  • photoUrl
  • customClaims
  • sessionClaims (nur beforeUserSignedIn)

Mit Ausnahme von sessionClaims werden alle geänderten Felder in der Datenbank von Firebase Authentication gespeichert. Das bedeutet, dass sie im Antworttoken enthalten sind und zwischen Nutzersitzungen erhalten bleiben.

Im folgenden Beispiel wird gezeigt, wie ein Standard-Anzeigename festgelegt wird:

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")

Wenn Sie einen Ereignis-Handler für beforeUserCreated und beforeUserSignedIn registrieren, beachten Sie, dass beforeUserSignedIn nach beforeUserCreated ausgeführt wird. In beforeUserCreated aktualisierte Nutzerfelder sind in beforeUserSignedIn sichtbar. Wenn Sie in beiden Event-Handlern ein anderes Feld als sessionClaims festlegen, überschreibt der in beforeUserSignedIn festgelegte Wert den in beforeUserCreated festgelegten Wert. Nur für sessionClaims werden sie auf die Tokenanforderungen der aktuellen Sitzung übertragen, aber nicht in der Datenbank gespeichert oder gespeichert.

Wenn beispielsweise sessionClaims festgelegt sind, werden sie von beforeUserSignedIn mit allen beforeUserCreated-Anforderungen zurückgegeben und zusammengeführt. Wenn ein sessionClaims-Schlüssel mit einem Schlüssel in customClaims übereinstimmt, werden die übereinstimmenden customClaims in den Tokenanforderungen vom sessionClaims-Schlüssel überschrieben. Der überschriebene customClaims-Schlüssel bleibt jedoch für zukünftige Anfragen in der Datenbank erhalten.

Unterstützte OAuth-Anmeldedaten und -Daten

Sie können OAuth-Anmeldedaten und -Daten an Blockierfunktionen von verschiedenen Identitätsanbietern übergeben. Die folgende Tabelle zeigt, welche Anmeldedaten und Daten für die einzelnen Identitätsanbieter unterstützt werden:

Identitätsanbieter ID-Token Access Token (Zugriffstoken) Ablaufzeit Token-Secret Aktualisierungs-Token Anmeldeanforderungen
Google Ja Ja Ja Nein Ja Nein
Facebook Nein Ja Ja Nein Nein Nein
Twitter Nein Ja Nein Ja Nein Nein
GitHub Nein Ja Nein Nein Nein Nein
Microsoft Ja Ja Ja Nein Ja Nein
LinkedIn Nein Ja Ja Nein Nein Nein
Yahoo Ja Ja Ja Nein Ja Nein
Apple Ja Ja Ja Nein Ja Nein
SAML Nein Nein Nein Nein Nein Ja
OIDC Ja Ja Ja Nein Ja Ja

OAuth-Tokens

Wenn Sie ein ID-Token, ein Zugriffstoken oder ein Aktualisierungstoken in einer Blockierfunktion verwenden möchten, müssen Sie zuerst das Kästchen auf der Seite Blockierfunktionen der Firebase-Konsole anklicken.

Aktualisierungstokens werden von Identitätsanbietern nicht zurückgegeben, wenn die Anmeldung direkt über OAuth-Anmeldedaten erfolgt, wie z. B. mit einem ID-Token oder Zugriffstoken. In diesem Fall werden die clientseitigen OAuth-Anmeldedaten an die Blockierfunktion übergeben.

In den folgenden Abschnitten werden die verschiedenen Arten von Identitätsanbietern und ihre unterstützten Anmeldedaten und Daten beschrieben.

Generische OIDC-Anbieter

Wenn sich ein Nutzer mit einem generischen OIDC-Anbieter anmeldet, werden die folgenden Anmeldedaten übergeben:

  • ID-Token: Wird angegeben, wenn der Ablauf id_token ausgewählt ist.
  • Zugriffstoken: Wird angegeben, wenn der Codeablauf ausgewählt ist Beachten Sie, dass der Codeablauf derzeit nur über die REST API unterstützt wird.
  • Aktualisierungstoken: Wird angegeben, wenn der offline_access-Bereich ausgewählt ist.

Beispiel:

const provider = new firebase.auth.OAuthProvider('oidc.my-provider');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);

Google

Wenn sich ein Nutzer mit Google anmeldet, werden die folgenden Anmeldedaten übergeben:

  • ID-Token
  • Zugriffstoken
  • Aktualisierungstoken: Wird nur angegeben, wenn die folgenden benutzerdefinierten Parameter angefordert werden:
    • access_type=offline
    • prompt=consent, wenn der Nutzer zuvor zugestimmt hat und kein neuer Bereich angefordert wurde

Beispiel:

import { getAuth, signInWithPopup, GoogleAuthProvider } from 'firebase/auth';

const auth = getAuth();
const provider = new GoogleAuthProvider();
provider.setCustomParameters({
  'access_type': 'offline',
  'prompt': 'consent'
});
signInWithPopup(auth, provider);

Weitere Informationen zu Google-Aktualisierungstokens

Facebook

Wenn sich ein Nutzer mit Facebook anmeldet, werden die folgenden Anmeldedaten übergeben:

  • Zugriffstoken: Ein Zugriffstoken wird zurückgegeben und kann durch ein anderes Zugriffstoken ersetzt werden. Weitere Informationen zu den verschiedenen Arten von Zugriffstokens, die von Facebook unterstützt werden, und wie Sie diese gegen langfristige Tokens tauschen können.

GitHub

Wenn sich ein Nutzer mit GitHub anmeldet, werden die folgenden Anmeldedaten übergeben:

  • Zugriffstoken: läuft nicht ab, es sei denn, es wird widerrufen.

Microsoft

Wenn sich ein Nutzer mit Microsoft anmeldet, werden die folgenden Anmeldedaten übergeben:

  • ID-Token
  • Zugriffstoken
  • Aktualisierungstoken: Wird an die Blockierfunktion übergeben, wenn der offline_access-Bereich ausgewählt ist.

Beispiel:

import { getAuth, signInWithPopup, OAuthProvider } from 'firebase/auth';

const auth = getAuth();
const provider = new OAuthProvider('microsoft.com');
provider.addScope('offline_access');
signInWithPopup(auth, provider);

Yahoo

Wenn sich ein Nutzer mit Spammer anmelden, werden die folgenden Anmeldedaten ohne benutzerdefinierte Parameter oder Bereiche übergeben:

  • ID-Token
  • Zugriffstoken
  • Aktualisierungstoken

LinkedIn

Wenn sich ein Nutzer mit LinkedIn anmeldet, werden folgende Anmeldedaten übergeben:

  • Zugriffstoken

Apple

Wenn sich ein Nutzer mit Apple anmeldet, werden die folgenden Anmeldedaten ohne benutzerdefinierte Parameter oder Bereiche übergeben:

  • ID-Token
  • Zugriffstoken
  • Aktualisierungstoken

Gängige Szenarien

Die folgenden Beispiele veranschaulichen gängige Anwendungsfälle für Blockierfunktionen:

Registrierung über eine bestimmte Domain zulassen

Das folgende Beispiel zeigt, wie Sie verhindern können, dass sich Nutzer, die nicht zur example.com-Domain gehören, bei Ihrer Anwendung registrieren:

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 (Vorabversion)

 @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",
           )

Nutzer mit unbestätigten E-Mails für die Registrierung blockieren

Das folgende Beispiel zeigt, wie Sie verhindern können, dass sich Nutzer mit unbestätigten E-Mails bei Ihrer Anwendung registrieren:

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.")

E-Mail-Adressen von bestimmten Identitätsanbietern als bestätigt behandeln

Das folgende Beispiel zeigt, wie Nutzer-E-Mails von bestimmten Identitätsanbietern als bestätigt behandelt werden:

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)

Anmeldung von bestimmten IP-Adressen blockieren

Im folgenden Beispiel wird gezeigt, wie die Anmeldung aus bestimmten IP-Adressbereichen blockiert wird:

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.")

Benutzerdefinierte Anforderungen und Sitzungsanforderungen festlegen

Im folgenden Beispiel wird gezeigt, wie benutzerdefinierte Anforderungen und Sitzungsanforderungen festgelegt werden:

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"]
        })

Tracking von IP-Adressen zum Überwachen verdächtiger Aktivitäten

Sie können den Diebstahl von Tokens verhindern, indem Sie die IP-Adresse erfassen, mit der sich ein Nutzer anmeldet, und diese mit der IP-Adresse bei nachfolgenden Anfragen vergleichen. Wenn die Anfrage verdächtig erscheint, z. B. weil die IP-Adressen aus verschiedenen geografischen Regionen stammen, können Sie den Nutzer auffordern, sich noch einmal anzumelden.

  1. Erfassen Sie mithilfe von Sitzungsanforderungen die IP-Adresse, mit der sich der Nutzer anmeldet:

    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})
    
  2. Wenn ein Nutzer versucht, auf Ressourcen zuzugreifen, die eine Authentifizierung mit Firebase Authentication erfordern, vergleichen Sie die IP-Adresse in der Anfrage mit der IP-Adresse, die für die Anmeldung verwendet wird:

    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 (Vorabversion)

    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)
    

Nutzerfotos bereinigen

Das folgende Beispiel zeigt, wie Sie Profilbilder von Nutzern bereinigen:

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)

Weitere Informationen zum Erkennen und Bereinigen von Bildern finden Sie in der Cloud Vision-Dokumentation.

Auf OAuth-Anmeldedaten eines Nutzeranbieters zugreifen

Das folgende Beispiel zeigt, wie Sie ein Aktualisierungstoken für einen Nutzer abrufen, der sich bei Google angemeldet hat, und damit die Google Calendar APIs aufrufen. Das Aktualisierungstoken wird für den Offlinespeicher gespeichert.

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-Bewertung für Nutzeraktionen überschreiben

Im folgenden Beispiel wird gezeigt, wie Sie ein reCAPTCHA Enterprise-Urteil für unterstützte Nutzerflüsse überschreiben.

Weitere Informationen zur Integration von reCAPTCHA Enterprise in die Firebase-Authentifizierung finden Sie unter reCAPTCHA Enterprise aktivieren.

Mit Blockierungsfunktionen können Sie Zugriffe basierend auf benutzerdefinierten Faktoren zulassen oder blockieren und so das von reCAPTCHA Enterprise bereitgestellte Ergebnis überschreiben.

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',
 }
});