Mở rộng Xác thực Firebase bằng các chức năng chặn


Chức năng chặn cho phép bạn thực thi mã tùy chỉnh nhằm sửa đổi kết quả của việc 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 của người dùng trước khi trả thông tin đó 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 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 thực hiện trước.

Hiểu các chức năng chặn

Bạn có thể đăng ký chức năng chặn cho hai 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ề ứng dụng khách của bạn.

  • beforeSignIn : 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 Xác thực Firebase trả lại mã thông báo ID cho ứng dụng khách của bạn. Nếu ứng dụng của bạn sử dụng xác thực đa yếu tố, chức năng này sẽ kích hoạt sau khi người dùng xác minh yếu tố thứ hai của họ. Lưu ý rằng việc tạo người dùng mới cũng kích hoạt beforeSignIn , ngoài beforeCreate .

Hãy ghi nhớ những điều sau khi sử dụng chức năng chặn:

  • Chức năng 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 trả về lỗi và thao tác máy khách không thành công.

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

  • Các hàm áp dụng cho tất cả người dùng trong dự án của bạn, bao gồm mọi người dùng có trong đối tượng thuê . 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 mọi đối tượng thuê mà họ thuộc về, để bạn có thể phản hồi tương ứng.

  • 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 chức năng beforeSignIn đã đăng ký.

  • Xác thực ẩn danh và tùy chỉnh không kích hoạt chức năng chặn.

Triển khai chức năng chặn

Để chèn mã tùy chỉnh của bạn vào luồng xác thực người dùng, hãy triển khai các chức năng chặn. Khi các chức năng chặn của bạn được triển khai, mã tùy 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 chức năng chặn giống như cách bạn triển khai bất kỳ chức năng nào. (xem trang Bắt đầu sử dụng chức năng đám mây để biết chi tiết). Tóm tắt:

  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 no-op sau 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 việc triển khai logic xác thực tùy chỉnh. Xem các phần sau để tìm hiểu cách triển khai các chức năng chặn của bạn và các trường hợp phổ biến để biết ví dụ cụ thể.

  2. Triển khai các chức năng của bạn bằng Firebase CLI:

    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 lần cập nhật chúng.

Lấy thông tin 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ề 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 Sự miêu tả Ví dụ
locale Ngôn ngữ ứng dụng. Bạn có thể đặt ngôn ngữ bằng SDK máy khách hoặc bằng cách chuyển tiêu đề ngôn ngữ trong REST API. 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 chức năng chặn. Mozilla/5.0 (X11; Linux x86_64)
eventId Mã định danh duy nhất của sự kiện. rWsyPtolplG2TBFoOkkgyg
eventType Loại sự kiện. Điều 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 quan được sử dụng, như Google hoặc email/mật khẩu. providers/cloud.auth/eventTypes/user.beforeSignIn:password
authType Luôn luôn USER . USER
resource Dự án hoặc đối tượng thuê Xác thực Firebase. projects/ project-id /tenants/ tenant-id
timestamp Thời gian sự kiện được kích hoạt, được định dạng dưới dạng chuỗi RFC 3339 . Tue, 23 Jul 2019 21:10:57 GMT
additionalUserInfo Một đối tượng chứa thông tin về người dùng. AdditionalUserInfo
credential Một đối tượng chứa thông tin về thông tin xác thực của người dùng. AuthCredential

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

Để chặn nỗ lực đăng ký hoặc đăng nhập, hãy ném HttpsError vào hàm của bạn. Ví dụ:

Node.js

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

Bảng sau liệt kê các lỗi bạn có thể nêu ra, cùng với thông báo lỗi mặc định của chúng:

Tên Mã số Tin nhắn
invalid-argument 400 Khách hàng đã chỉ định một đối số không hợp lệ.
failed-precondition 400 Yêu cầu không thể được thực hiện ở trạng thái hệ thống hiện tại.
out-of-range 400 Khách hàng đã chỉ định một 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 Khách hàng 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-ghi.
already-exists 409 Tài nguyên mà khách hàng cố gắng tạo đã tồn tại.
resource-exhausted 429 Hết hạn ngạch tài nguyên hoặc đạt đến giới hạn tốc độ.
cancelled 499 Yêu cầu bị hủy bởi khách hàng.
data-loss 500 Mất dữ liệu không thể phục hồi hoặc hỏng dữ liệu.
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 Phương thức API không được máy chủ triển khai.
unavailable 503 Dịch vụ Không sẵn có.
deadline-exceeded 504 Đã vượt quá thời hạn yêu cầu.

Bạn cũng có thể chỉ định một thông báo lỗi tùy 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 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 tùy chỉnh, Cloud Functions sẽ gói lỗi và trả về 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ý tương ứng. 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 nỗ lực đăng ký hoặc đăng nhập, bạn có thể cho phép thao tác tiếp tục nhưng sửa đổi đối tượng User được lưu vào cơ sở dữ liệu của Xác thực Firebase và được trả về máy 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 Xác thực Firebase, có nghĩa là chúng được đưa vào mã thông báo phản hồi và tồn tại giữa các phiên của người dùng.

Ví dụ sau đây cho thấ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 đặt trường khác với sessionClaims trong cả hai trình xử lý sự kiện, thì giá trị được đặt trong beforeSignIn sẽ ghi đè giá trị được đặt trong beforeCreate . Chỉ dành cho sessionClaims , chúng được truyền tới các yêu cầ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ất kỳ sessionClaims được đặt, beforeSignIn sẽ trả về chúng cùng với bất kỳ xác nhận quyền beforeCreate và chúng sẽ được hợp nhất. Khi chúng được hợp nhất, nếu khóa sessionClaims khớp với khóa trong customClaims thì customClaims phù hợp sẽ bị ghi đè trong xác nhận quyền sở hữu mã thông báo bằng khóa sessionClaims . Tuy nhiên, khóa customClaims bị ghi đè sẽ vẫn được lưu giữ trong cơ sở dữ liệu cho các yêu cầu trong tương lai.

Thông tin xác thực và dữ liệu OAuth được hỗ trợ

Bạn có thể chuyển thông tin xác thực và dữ liệu OAuth tới các chức năng chặn từ nhiều nhà cung cấp danh tính khác nhau. Bảng sau đây hiển thị 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 danh tính Mã thông báo ID Truy cập thẻ Thời gian hết hạn Bí mật mã thông báo Làm mới mã thông báo Yêu cầu đăng nhập
Google Đúng Đúng Đúng KHÔNG Đúng KHÔNG
Facebook KHÔNG Đúng Đúng KHÔNG KHÔNG KHÔNG
Twitter KHÔNG Đúng KHÔNG Đúng KHÔNG KHÔNG
GitHub KHÔNG Đúng KHÔNG KHÔNG KHÔNG KHÔNG
Microsoft Đúng Đúng Đúng KHÔNG Đúng KHÔNG
LinkedIn KHÔNG Đúng Đúng KHÔNG KHÔNG KHÔNG
Yahoo Đúng Đúng Đúng KHÔNG Đúng KHÔNG
Quả táo Đúng Đúng Đúng KHÔNG Đúng KHÔNG
SAML KHÔNG KHÔNG KHÔNG KHÔNG KHÔNG Đúng
OIDC Đúng Đúng Đúng KHÔNG Đúng Đúng

Làm mới mã thông báo

Để sử dụng mã thông báo làm mới trong chức năng chặn, trước tiên bạn phải chọn hộp kiểm trên trang Chức năng chặn của bảng điều khiển Firebase.

Bất kỳ nhà cung cấp danh tính nào sẽ không trả lại mã thông báo 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 ID hoặc mã thông báo truy cập. Trong trường hợp này, thông tin xác thực OAuth phía máy khách tương tự sẽ được chuyển đến chức năng 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ợ của họ.

Nhà cung cấp OIDC chung

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

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

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, thông tin đăng nhập sau sẽ được chuyển:

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

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ã thông báo làm mới của Google .

Facebook

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

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

GitHub

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

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

Microsoft

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

  • mã thông báo ID
  • Truy cập thẻ
  • Mã thông báo làm mới : Được chuyển tới chức năng chặn nếu phạm vi offline_access được chọn.

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 đăng nhập sau sẽ được chuyển mà không có bất kỳ tham số hoặc phạm vi tùy chỉnh nào:

  • mã thông báo ID
  • Truy cập thẻ
  • Làm mới mã thông báo

LinkedIn

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

  • Truy cập thẻ

Quả táo

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

  • mã thông báo ID
  • Truy cập thẻ
  • Làm mới mã thông báo

Các tình huống phổ biến

Các ví dụ sau minh họa một số trường hợp sử dụng phổ biến cho các chức năng chặn:

Chỉ cho phép đăng ký từ một tên 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ý bằng ứ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 thấy cách ngăn người dùng có email chưa được xác minh đă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.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 thấy 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.`);
  }
});

Xử lý một số email của nhà cung cấp danh tính nhất định là đã được xác minh

Ví dụ sau đây cho thấy cách xử lý email người dùng từ một số nhà cung cấp danh tính nhất định là đã được 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 về cách chặn đăng nhập từ các 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 xác nhận quyền sở hữu tùy chỉnh và phiên

Ví dụ sau đây cho thấy cách đặt xác nhận quyền sở hữu tùy chỉnh và 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 trộm cắp mã thông báo bằng cách theo dõi địa chỉ IP mà 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ừ các khu vực địa lý khác nhau — 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 các tài nguyên yêu cầu xác thực bằng Xác thực Firebase, hãy so sánh địa chỉ IP trong yêu cầu với IP được sử 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!' })
          });
        }
      });
    });
    

Sàng lọc ảnh người dùng

Ví dụ sau đây cho thấy cách vệ sinh ả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à vệ sinh hình ảnh, hãy xem tài liệu Cloud Vision .

Truy cập 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 đây minh họa cách lấy mã thông báo 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ã thông báo làm mới được lưu trữ để truy cập ngoại tuyến.

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ả reCAPTCHA Enterprise đối với hoạt động của người dùng

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

Tham khảo Bật reCAPTCHA Enterprise để tìm hiểu thêm về cách tích hợp reCAPTCHA Enterprise với Xác thực Firebase.

Chức năng chặn có thể được sử dụng để cho phép hoặc chặn các luồng dựa trên các yếu tố tùy 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',
 };
});