屏蔽 Auth 触发器(续1)

}); }); ```

### Python

``` from firebase_admin import auth, initialize_app import flask

initialize_app() flask_app = flask.Flask(name)

@flask_app.post() def get_restricted_data(req: flask.Request): # Get the ID token passed. id_token = req.json().get("idToken")

   # Verify the ID token, check if revoked, and decode its payload.
   try:
       claims = auth.verify_id_token(id_token, check_revoked=True)
   except:
       return flask.Response(status=500)

   # Get request IP address.
   request_ip = req.remote_addr

   # Get sign-in IP address.
   signin_ip = claims["signInIpAddress"]

   # Check if the request IP address origin is suspicious relative to
   # the session IP addresses. The current request timestamp and the
   # auth_time of the ID token can provide additional signals of abuse,
   # especially if the IP address suddenly changed. If there was a sudden
   # geographical change in a short period of time, then it will give
   # stronger signals of possible abuse.
   if is_suspicious_change(signin_ip, request_ip):
       # Suspicious IP address change. Require re-authentication.
       # You can also revoke all user sessions by calling:
       #   auth.revoke_refresh_tokens(claims["sub"])
       return flask.Response(status=401,
                             response="Unauthorized access. Sign in again!")
   else:
       # Access is valid. Try to return data.
       return data_from_claims(claims)

```

过滤用户照片

以下示例展示了如何清理用户的个人资料照片:

Node.js

export const beforecreated = beforeUserCreated((event) => {
  const user = event.data;
  if (user.photoURL) {
    return isPhotoAppropriate(user.photoURL)
      .then((status) => {
        if (!status) {
          // Sanitize inappropriate photos by replacing them with guest photos.
          // Users could also be blocked from sign-up, disabled, etc.
          return {
            photoUrl: PLACEHOLDER_GUEST_PHOTO_URL,
          };
        }
      });
});

Python

@identity_fn.before_user_created()
def sanitizeprofilephoto(
        event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None:
    if event.data.photo_url is not None:
        score = analyze_photo_with_ml(event.data.photo_url)
        if score > THRESHOLD:
            return identity_fn.BeforeCreateResponse(photo_url=PLACEHOLDER_URL)

main.py

如需详细了解如何检测和清理图片,请参阅 Cloud Vision 文档。

访问用户的身份提供方的 OAuth 凭据

以下示例展示了如何为使用 Google 账号登录的用户获取刷新令牌,并使用该令牌调用 Google Calendar API。系统会存储刷新令牌以供离线访问时使用。

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)

main.py

替换用户操作的 reCAPTCHA Enterprise 判定结果

以下示例展示了如何替换受支持的用户体验流程的 reCAPTCHA Enterprise 判定结果。

如需详细了解如何将 reCAPTCHA Enterprise 与 Firebase Authentication 集成,请参阅启用 reCAPTCHA Enterprise。

屏蔽函数可用于根据自定义因素允许或屏蔽流程,从而替换 reCAPTCHA Enterprise 提供的结果。

Node.js

const { beforeSmsSent } = require("firebase-functions/v2/identity");
exports.beforesmssentv2 = beforeSmsSent((event) => {
 if (
   event.smsType === "SIGN_IN_OR_SIGN_UP" &&
   event.additionalUserInfo.phoneNumber.includes('+91')
 ) {
   return {
     recaptchaActionOverride: "ALLOW",
   };
 }

 // Allow users to sign in with recaptcha score greater than 0.5
 if (event.additionalUserInfo.recaptchaScore > 0.5) {
   return {
     recaptchaActionOverride: 'ALLOW',
   };
 }

 // Block all others.
 return  {
   recaptchaActionOverride: 'BLOCK',
 }
});