Mở rộng tính năng Xác thực Firebase bằng các hàm chặn


Hàm chặn cho phép bạn thực thi mã tuỳ chỉnh sửa đổi kết quả người dùng đăng ký hoặc đăng nhập vào ứng dụng của bạn. Ví dụ: bạn có thể ngăn người dùng xác thực nếu họ không đáp ứng các tiêu chí nhất định hoặc cập nhật thông tin người dùng trước khi trả về ứng dụng khách của bạn.

Trước khi bắt đầu

Để sử dụng các chức năng chặn, bạn phải nâng cấp dự án Firebase của mình lên tính năng Xác thực Firebase bằng Nền tảng nhận dạng. Nếu bạn chưa nâng cấp, hãy nâng cấp trước.

Tìm hiểu về hàm chặn

Bạn có thể đăng ký các hàm chặn cho 2 sự kiện:

  • beforeCreate: Kích hoạt trước khi người dùng mới được lưu vào cơ sở dữ liệu Xác thực Firebase và trước khi mã thông báo được trả về cho ứng dụng khách của bạn.

  • beforeSignIn: Điều kiện kích hoạt sau khi thông tin xác thực của người dùng được xác minh, nhưng trước khi tính năng Xác thực Firebase trả về một mã thông báo mã nhận dạng cho ứng dụng khách. Nếu ứng dụng của bạn sử dụng tính năng xác thực đa yếu tố, thì hàm sẽ kích hoạt sau khi người dùng xác minh yếu tố thứ hai. Xin lưu ý rằng việc tạo một người dùng mới cũng sẽ kích hoạt beforeSignIn, ngoài beforeCreate.

Hãy lưu ý những điều sau khi sử dụng hàm chặn:

  • Hàm của bạn phải phản hồi trong vòng 7 giây. Sau 7 giây, Xác thực Firebase sẽ trả về lỗi và thao tác ứng dụng không thành công.

  • Các mã phản hồi HTTP không phải 200 sẽ được chuyển đến ứng dụng khách của bạn. Đảm bảo mã ứng dụng xử lý mọi lỗi mà hàm có thể trả về.

  • Các hàm áp dụng cho toàn bộ người dùng trong dự án của bạn, bao gồm cả mọi người dùng nằm trong một đối tượng thuê. Tính năng Xác thực Firebase cung cấp thông tin về người dùng cho chức năng của bạn, bao gồm cả mọi đối tượng thuê của họ để bạn có thể đưa ra câu trả lời phù hợp.

  • Việc liên kết một nhà cung cấp danh tính khác với một tài khoản sẽ kích hoạt lại mọi hàm beforeSignIn đã đăng ký.

  • Phương thức xác thực ẩn danh và tuỳ chỉnh không kích hoạt các chức năng chặn.

Triển khai hàm chặn

Để chèn mã tuỳ chỉnh vào quy trình xác thực người dùng, hãy triển khai các hàm chặn. Sau khi triển khai các chức năng chặn, mã tuỳ chỉnh của bạn phải hoàn tất thành công để xác thực và tạo người dùng thành công.

Bạn triển khai hàm chặn giống như cách triển khai bất kỳ hàm nào. (xem trang Bắt đầu của Cloud Functions để biết thông tin chi tiết). Tóm lại:

  1. Viết các Hàm đám mây xử lý sự kiện beforeCreate, sự kiện beforeSignIn hoặc cả hai.

    Ví dụ: để bắt đầu, bạn có thể thêm các hàm không hoạt động sau đây vào index.js:

    const functions = require('firebase-functions');
    
    exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
      // TODO
    });
    
    exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
      // TODO
    });
    

    Các ví dụ ở trên đã bỏ qua bước triển khai logic xác thực tuỳ chỉnh. Hãy xem các phần sau đây để tìm hiểu cách triển khai các hàm chặn và Các trường hợp phổ biến để biết các ví dụ cụ thể.

  2. Triển khai các hàm bằng Giao diện dòng lệnh (CLI) của Firebase:

    firebase deploy --only functions
    

    Bạn phải triển khai lại các chức năng của mình mỗi khi cập nhật chúng.

Nhận thông tin về người dùng và bối cảnh

Các sự kiện beforeSignInbeforeCreate cung cấp các đối tượng UserEventContext chứa thông tin về việc người dùng đăng nhập. Hãy sử dụng các giá trị này trong mã của bạn để xác định xem có cho phép một thao tác tiếp tục hay không.

Để biết danh sách các thuộc tính có sẵn trên đối tượng User, hãy xem tài liệu tham khảo API UserRecord.

Đối tượng EventContext chứa các thuộc tính sau:

Tên Mô tả Ví dụ
locale Ngôn ngữ của ứng dụng. Bạn có thể đặt ngôn ngữ bằng cách sử dụng SDK ứng dụng hoặc bằng cách truyền tiêu đề ngôn ngữ trong API REST. fr hoặc sv-SE
ipAddress Địa chỉ IP của thiết bị mà người dùng cuối đang đăng ký hoặc đăng nhập. 114.14.200.1
userAgent Tác nhân người dùng kích hoạt hàm chặn. Mozilla/5.0 (X11; Linux x86_64)
eventId Giá trị nhận dạng riêng biệt của sự kiện. rWsyPtolplG2TBFoOkkgyg
eventType Loại sự kiện. Phương thức này cung cấp thông tin về tên sự kiện (chẳng hạn như beforeSignIn hoặc beforeCreate) và phương thức đăng nhập liên kết đã sử dụng, chẳng hạn như Google hoặc email/mật khẩu. providers/cloud.auth/eventTypes/user.beforeSignIn:password
authType Luôn là USER. USER
resource Dự án Xác thực Firebase hoặc đối tượng thuê. projects/project-id/tenants/tenant-id
timestamp Thời gian sự kiện được kích hoạt, có định dạng là chuỗi RFC 3339. Tue, 23 Jul 2019 21:10:57 GMT
additionalUserInfo Đối tượng chứa thông tin về người dùng. AdditionalUserInfo
credential Đối tượng chứa thông tin về thông tin đăng nhập của người dùng. AuthCredential

Chặn đăng ký hoặc đăng nhập

Để chặn một hoạt động đăng ký hoặc đăng nhập, hãy gửi một HttpsError vào hàm của bạn. Ví dụ:

Node.js

throw new functions.auth.HttpsError('permission-denied');

Bảng sau đây liệt kê các lỗi mà bạn có thể gặp phải, cùng với thông báo lỗi mặc định:

Tên Nội dung
invalid-argument 400 Ứng dụng khách chỉ định đối số không hợp lệ
failed-precondition 400 Không thể thực thi yêu cầu trong tình trạng hệ thống hiện tại.
out-of-range 400 Ứng dụng khách chỉ định phạm vi không hợp lệ.
unauthenticated 401 Mã thông báo OAuth bị thiếu, không hợp lệ hoặc đã hết hạn.
permission-denied 403 Ứng dụng khách không có đủ quyền.
not-found 404 Không tìm thấy tài nguyên được chỉ định.
aborted 409 Xung đột đồng thời, chẳng hạn như xung đột đọc-sửa đổi-ghi.
already-exists 409 Tài nguyên mà ứng dụng khách tìm cách tạo đã tồn tại.
resource-exhausted 429 Hết định mức tài nguyên hoặc đã đạt đến tốc độ giới hạn.
cancelled 499 Ứng dụng khách đã hủy yêu cầu.
data-loss 500 Mất hoặc hư hỏng dữ liệu và không phục hồi được.
unknown 500 Lỗi máy chủ không xác định.
internal 500 Lỗi máy chủ nội bộ.
not-implemented 501 Máy chủ không triển khai phương thức API.
unavailable 503 Dịch vụ hiện không hoạt động.
deadline-exceeded 504 Đã quá hạn chót cho yêu cầu.

Bạn cũng có thể chỉ định thông báo lỗi tuỳ chỉnh:

Node.js

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

Ví dụ sau đây cho thấy cách chặn những người dùng không thuộc một miền cụ thể đăng ký ứng dụng của bạn:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  // (If the user is authenticating within a tenant context, the tenant ID can be determined from
  // user.tenantId or from context.resource, e.g. 'projects/project-id/tenant/tenant-id-1')

  // Only users of a specific domain can sign up.
  if (user.email.indexOf('@acme.com') === -1) {
    throw new functions.auth.HttpsError('invalid-argument', `Unauthorized email "${user.email}"`);
  }
});

Bất kể bạn sử dụng thông báo mặc định hay tuỳ chỉnh, Cloud Functions vẫn sẽ gói lỗi và trả về lỗi cho máy khách dưới dạng lỗi nội bộ. Ví dụ:

throw new functions.auth.HttpsError('invalid-argument', `Unauthorized email user@evil.com}`);

Ứng dụng của bạn sẽ phát hiện lỗi và xử lý lỗi đó phù hợp. Ví dụ:

JavaScript

// Blocking functions can also be triggered in a multi-tenant context before user creation.
// firebase.auth().tenantId = 'tenant-id-1';
firebase.auth().createUserWithEmailAndPassword('johndoe@example.com', 'password')
  .then((result) => {
    result.user.getIdTokenResult()
  })
  .then((idTokenResult) => {
    console.log(idTokenResult.claim.admin);
  })
  .catch((error) => {
    if (error.code !== 'auth/internal-error' && error.message.indexOf('Cloud Function') !== -1) {
      // Display error.
    } else {
      // Registration succeeds.
    }
  });

Sửa đổi người dùng

Thay vì chặn một hoạt động đăng ký hoặc đăng nhập, bạn có thể cho phép thao tác tiếp tục, nhưng hãy sửa đổi đối tượng User được lưu vào cơ sở dữ liệu của tính năng Xác thực Firebase và trả về ứng dụng khách.

Để sửa đổi người dùng, hãy trả về một đối tượng từ trình xử lý sự kiện có chứa các trường cần sửa đổi. Bạn có thể sửa đổi các trường sau:

  • displayName
  • disabled
  • emailVerified
  • photoUrl
  • customClaims
  • sessionClaims (chỉ beforeSignIn)

Ngoại trừ sessionClaims, tất cả các trường đã sửa đổi đều được lưu vào cơ sở dữ liệu của tính năng Xác thực Firebase, tức là các trường đó sẽ được đưa vào mã thông báo phản hồi và duy trì giữa các phiên của người dùng.

Ví dụ sau đây trình bày cách đặt tên hiển thị mặc định:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  return {
    // If no display name is provided, set it to "Guest".
    displayName: user.displayName || 'Guest';
  };
});

Nếu bạn đăng ký một trình xử lý sự kiện cho cả beforeCreatebeforeSignIn, hãy lưu ý rằng beforeSignIn sẽ thực thi sau beforeCreate. Các trường người dùng được cập nhật trong beforeCreate sẽ hiển thị trong beforeSignIn. Nếu bạn thiết lập một trường không phải sessionClaims trong cả hai trình xử lý sự kiện, thì giá trị đặt trong beforeSignIn sẽ ghi đè giá trị đặt trong beforeCreate. Chỉ đối với sessionClaims, các giá trị này sẽ được truyền đến các thông báo xác nhận quyền sở hữu mã thông báo của phiên hiện tại, nhưng không được duy trì hoặc lưu trữ trong cơ sở dữ liệu.

Ví dụ: nếu bạn đặt sessionClaims bất kỳ, thì beforeSignIn sẽ trả về các thông báo đó cùng với mọi thông báo xác nhận quyền sở hữu beforeCreate và các thông báo này sẽ được hợp nhất. Khi các khoá này được hợp nhất, nếu khoá sessionClaims khớp với một khoá trong customClaims, thì customClaims trùng khớp sẽ bị khoá sessionClaims ghi đè trong phần xác nhận quyền sở hữu mã thông báo. Tuy nhiên, khoá customClaims bị vượt quá vẫn sẽ được duy trì trong cơ sở dữ liệu cho các yêu cầu trong tương lai.

Dữ liệu và thông tin đăng nhập OAuth được hỗ trợ

Bạn có thể truyền thông tin đăng nhập và dữ liệu OAuth để chặn các hàm từ nhiều nhà cung cấp danh tính. Bảng sau đây cho biết những thông tin xác thực và dữ liệu nào được hỗ trợ cho từng nhà cung cấp danh tính:

Nhà cung cấp nhận dạng Mã thông báo giá trị nhận dạng Mã thông báo truy cập Thời gian hết hạn Bí mật mã thông báo Mã làm mới Xác nhận quyền sở hữu đăng nhập
Google Không Không
Facebook Không Không Không Không
Twitter Không Không Không Không
GitHub Không Không Không Không Không
Microsoft Không Không
LinkedIn Không Không Không Không
Yahoo Không Không
Apple Không Không
SAML Không Không Không Không Không
OIDC (OpenID Connect) Không

Làm mới mã

Để sử dụng mã làm mới trong một hàm chặn, trước tiên, bạn phải chọn hộp đánh dấu trên trang Hàm chặn trong bảng điều khiển của Firebase.

Bất kỳ nhà cung cấp danh tính nào sẽ không trả về mã làm mới khi đăng nhập trực tiếp bằng thông tin xác thực OAuth, chẳng hạn như mã thông báo nhận dạng hoặc mã truy cập. Trong trường hợp này, thông tin đăng nhập OAuth phía máy khách tương tự sẽ được chuyển đến hàm chặn.

Các phần sau đây mô tả từng loại nhà cung cấp danh tính cũng như thông tin xác thực và dữ liệu được hỗ trợ.

Nhà cung cấp OIDC chung

Khi người dùng đăng nhập bằng một nhà cung cấp OIDC chung, các thông tin xác thực sau sẽ được chuyển:

  • Mã thông báo giá trị nhận dạng: Được cung cấp nếu quy trình id_token được chọn.
  • Mã truy cập: Được cung cấp nếu quy trình mã được chọn. Xin lưu ý rằng luồng mã hiện chỉ được hỗ trợ thông qua API REST.
  • Làm mới mã thông báo: Được cung cấp nếu chọn phạm vi offline_access.

Ví dụ:

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

Google

Khi người dùng đăng nhập bằng Google, các thông tin đăng nhập sau sẽ được chuyển:

  • Mã thông báo giá trị nhận dạng
  • Mã truy cập
  • Làm mới mã thông báo: Chỉ được cung cấp nếu các thông số tuỳ chỉnh sau được yêu cầu:
    • access_type=offline
    • prompt=consent, nếu người dùng trước đây đã đồng ý và không có yêu cầu phạm vi mới nào

Ví dụ:

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

Tìm hiểu thêm về mã làm mới của Google.

Facebook

Khi người dùng đăng nhập bằng Facebook, thông tin đăng nhập sau đây sẽ được chuyển:

  • Mã truy cập: Mã truy cập được trả về và có thể đổi lấy một mã truy cập khác. Tìm hiểu thêm về các loại mã truy cập mà Facebook hỗ trợ và cách đổi chúng lấy mã thông báo dài hạn.

GitHub

Khi người dùng đăng nhập bằng GitHub, thông tin đăng nhập sau đây sẽ được chuyển:

  • Mã truy cập: Không hết hạn trừ phi bị thu hồi.

Microsoft

Khi người dùng đăng nhập bằng Microsoft, thông tin đăng nhập sau đây sẽ được chuyển:

  • Mã thông báo giá trị nhận dạng
  • Mã truy cập
  • Làm mới mã thông báo: Được chuyển đến hàm chặn nếu bạn chọn phạm vi offline_access.

Ví dụ:

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

Yahoo

Khi người dùng đăng nhập bằng Yahoo, thông tin xác thực sau sẽ được chuyển mà không có bất kỳ phạm vi hoặc thông số tuỳ chỉnh nào:

  • Mã thông báo giá trị nhận dạng
  • Mã truy cập
  • Làm mới mã thông báo

LinkedIn

Khi người dùng đăng nhập bằng LinkedIn, thông tin đăng nhập sau đây sẽ được chuyển:

  • Mã truy cập

Apple

Khi người dùng đăng nhập bằng Apple, thông tin xác thực sau đây sẽ được chuyển mà không có thông số hoặc phạm vi tuỳ chỉnh nào:

  • Mã thông báo giá trị nhận dạng
  • Mã truy cập
  • Làm mới mã thông báo

Các trường hợp phổ biến

Các ví dụ sau đây minh hoạ một số trường hợp sử dụng hàm chặn phổ biến:

Chỉ cho phép đăng ký từ một miền cụ thể

Ví dụ sau đây cho biết cách ngăn người dùng không thuộc miền example.com đăng ký với ứng dụng của bạn:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (!user.email || user.email.indexOf('@example.com') === -1) {
    throw new functions.auth.HttpsError(
      'invalid-argument', `Unauthorized email "${user.email}"`);
  }
});

Chặn người dùng có email chưa được xác minh đăng ký

Ví dụ sau đây cho biết cách ngăn người dùng có email chưa xác minh đăng ký ứng dụng của bạn:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (user.email && !user.emailVerified) {
    throw new functions.auth.HttpsError(
      'invalid-argument', `Unverified email "${user.email}"`);
  }
});

Yêu cầu xác minh email khi đăng ký

Ví dụ sau đây cho biết cách yêu cầu người dùng xác minh email của họ sau khi đăng ký:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  const locale = context.locale;
  if (user.email && !user.emailVerified) {
    // Send custom email verification on sign-up.
    return admin.auth().generateEmailVerificationLink(user.email).then((link) => {
      return sendCustomVerificationEmail(user.email, link, locale);
    });
  }
});

exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
 if (user.email && !user.emailVerified) {
   throw new functions.auth.HttpsError(
     'invalid-argument', `"${user.email}" needs to be verified before access is granted.`);
  }
});

Xem một số email của nhà cung cấp danh tính là đã xác minh

Ví dụ sau đây cho biết cách xem email của người dùng từ một số nhà cung cấp danh tính nhất định là đã xác minh:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (user.email && !user.emailVerified && context.eventType.indexOf(':facebook.com') !== -1) {
    return {
      emailVerified: true,
    };
  }
});

Chặn đăng nhập từ một số địa chỉ IP nhất định

Ví dụ sau đây về cách chặn hoạt động đăng nhập từ một số dải địa chỉ IP nhất định:

Node.js

exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
  if (isSuspiciousIpAddress(context.ipAddress)) {
    throw new functions.auth.HttpsError(
      'permission-denied', 'Unauthorized access!');
  }
});

Đặt thông báo xác nhận quyền sở hữu phiên và tuỳ chỉnh

Ví dụ sau đây trình bày cách đặt thông báo xác nhận quyền sở hữu tuỳ chỉnh và theo phiên:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (context.credential &&
      context.credential.providerId === 'saml.my-provider-id') {
    return {
      // Employee ID does not change so save in persistent claims (stored in
      // Auth DB).
      customClaims: {
        eid: context.credential.claims.employeeid,
      },
      // Copy role and groups to token claims. These will not be persisted.
      sessionClaims: {
        role: context.credential.claims.role,
        groups: context.credential.claims.groups,
      }
    }
  }
});

Theo dõi địa chỉ IP để giám sát hoạt động đáng ngờ

Bạn có thể ngăn chặn hành vi đánh cắp mã thông báo bằng cách theo dõi địa chỉ IP của người dùng đăng nhập và so sánh địa chỉ đó với địa chỉ IP trong các yêu cầu tiếp theo. Nếu yêu cầu có vẻ đáng ngờ – ví dụ: IP đến từ nhiều khu vực địa lý – bạn có thể yêu cầu người dùng đăng nhập lại.

  1. Sử dụng xác nhận quyền sở hữu phiên để theo dõi địa chỉ IP mà người dùng đăng nhập:

    Node.js

    exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
      return {
        sessionClaims: {
          signInIpAddress: context.ipAddress,
        },
      };
    });
    
  2. Khi người dùng cố gắng truy cập vào các tài nguyên yêu cầu xác thực bằng tính năng Xác thực Firebase, hãy so sánh địa chỉ IP trong yêu cầu với IP được dùng để đăng nhập:

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

Đang sàng lọc ảnh của người dùng

Ví dụ sau đây minh hoạ cách dọn dẹp ảnh hồ sơ của người dùng:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  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,
          };
        }
      });
});

Để tìm hiểu thêm về cách phát hiện và dọn dẹp hình ảnh, hãy xem tài liệu về Cloud Vision.

Truy cập vào thông tin xác thực OAuth của nhà cung cấp danh tính của người dùng

Ví dụ sau minh hoạ cách lấy mã làm mới cho người dùng đã đăng nhập bằng Google và sử dụng mã đó để gọi API Lịch Google. Mã làm mới được lưu trữ để bạn có thể truy cập khi không có mạng.

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

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (context.credential &&
      context.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,
        context.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:
          // context.additionalUserInfo.profile.granted_scopes (space joined list of scopes).

          // Set access token/refresh token.
          oAuth2Client.setCredentials({
            access_token: context.credential.accessToken,
            refresh_token: context.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();
          });
      });
    })
  }
});

Ghi đè kết quả của reCAPTCHA Enterprise cho hoạt động của người dùng

Ví dụ sau đây cho thấy cách ghi đè một kết quả reCAPTCHA Enterprise cho các luồng người dùng được hỗ trợ.

Hãy tham khảo bài viết Bật reCAPTCHA Enterprise để tìm hiểu thêm về cách tích hợp reCAPTCHA Enterprise với tính năng xác thực Firebase.

Bạn có thể dùng các hàm chặn để cho phép hoặc chặn luồng dựa trên các yếu tố tuỳ chỉnh, từ đó ghi đè kết quả do reCAPTCHA Enterprise cung cấp.

Node.js

 const {
   auth,
 } = require("firebase-functions/v1");

exports.checkrecaptchaV1 = auth.user().beforeSignIn((userRecord, context) => {
 // Allow users with a specific email domain to sign in regardless of their recaptcha score.
 if (userRecord.email && userRecord.email.indexOf('@acme.com') === -1) {
   return {
     recaptchaActionOverride: 'ALLOW',
   };
 }

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

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