Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Mở rộng Xác thực Firebase với chặn Chức năng đám mây, Mở rộng xác thực Firebase với chặn Chức năng đám mây

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Nếu bạn đã nâng cấp lên Xác thực Firebase bằng Nền tảng nhận dạng , bạn có thể mở rộng Xác thực Firebase bằng cách chặn các Chức năng đám mây .

Chức năng chặn cho phép bạn thực thi mã tùy chỉnh 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ả lại cho ứ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 làm như vậy trước.

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

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

  • beforeSignIn : Kích hoạt sau khi thông tin đăng nhập của người dùng được xác minh, nhưng trước khi Xác thực Firebase trả về 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 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 các 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à hoạt động ứng dụng không thành công.

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

  • Các chức năng áp dụng cho tất cả người dùng trong dự án của bạn, bao gồm bất kỳ người dùng nào 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 bất kỳ người thuê nào mà họ thuộc về, vì vậy bạn có thể trả lời phù hợp.

  • Việc liên kết nhà cung cấp danh tính khác với 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 các chức năng chặn.

Triển khai và đăng ký một chức năng chặn

Để chèn mã tùy chỉnh của bạn vào quy trình xác thực người dùng, hãy triển khai và đăng ký các chức năng chặn. Sau khi các chức năng chặn của bạn được triển khai và đăng ký, 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.

Triển khai một chức năng chặn

Bạn triển khai một 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 chức năng đám mây để biết thêm 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 các 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 khi cập nhật chúng.

Đăng ký chức năng chặn

  1. Truy cập trang Cài đặt xác thực Firebase trong bảng điều khiển Firebase.

  2. Chọn tab Chức năng chặn .

  3. Đăng ký chức năng chặn của bạn bằng cách chọn nó từ menu thả xuống trong Trước khi tạo tài khoản (beforeCreate) hoặc Trước khi đăng nhập (beforeSignIn) .

  4. Lưu các thay đổi của bạn.

Nhận thông tin về người dùng và ngữ 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. 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 hoạt động 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 tham chiếu API UserRecord .

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

Tên Sự mô tả Thí dụ
locale Ngôn ngữ ứng dụng. Bạn có thể đặt ngôn ngữ bằng cách sử dụng SDK ứng dụng khách hoặc bằng cách chuyể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 chức năng chặn. Mozilla/5.0 (X11; Linux x86_64)
eventId Giá trị nhận dạng 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 USER . USER
resource Đối tượng hoặc dự án 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 đăng nhập của người dùng. AuthCredential

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

Để chặn đăng ký hoặc nỗ lực đăng nhập, hãy HttpsError trong chức năng 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ố Thông điệp
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 trong 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 Tài nguyên được chỉ định không được tìm thấy.
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à khách hàng đã cố gắng tạo đã tồn tại.
resource-exhausted 429 Ngoài hạn ngạch tài nguyên hoặc giới hạn tốc độ đạt đến.
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 dữ liệu bị hỏng.
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 ở trong 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ẽ loại bỏ 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 ra lỗi và xử lý nó cho 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 đăng ký hoặc nỗ lực đăng nhập, bạn có thể cho phép hoạt động 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à trả lại cho 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ủa bạn có chứa các trường để 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 Firebase Authentication, có nghĩa là chúng được đưa vào mã 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 thực thi sau beforeCreate . Các trường người dùng được cập nhật trong beforeCreate được hiển thị trong beforeSignIn . Nếu bạn đặt một trường không phải là sessionClaims trong cả hai trình xử lý sự kiện, giá trị được đặt trong beforeSignIn ghi đè giá trị được đặt trong beforeCreate . Chỉ đối với 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 tồn tại hoặc được lưu trữ trong cơ sở dữ liệu.

Ví dụ: nếu bất kỳ sessionClaims nào được đặt, beforeSignIn sẽ trả về chúng cùng với bất kỳ yêu cầu nào beforeCreate và chúng sẽ được hợp nhất. Khi chúng được hợp nhất, nếu một khóa sessionClaims khớp với một khóa trong customClaims , thì khóa customClaims phù hợp sẽ được 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 sẽ vẫn còn trong cơ sở dữ liệu cho các yêu cầu trong tương lai.

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

Bạn có thể chuyển dữ liệu và thông tin xác thực OAuth cho các chức năng chặn từ các nhà cung cấp danh tính khác nhau. Bảng sau đây cho thấy 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 Tuyên bố đă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ã làm mới trong một 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.

Mã làm mới sẽ không được trả lại bởi bất kỳ nhà cung cấp danh tính nào 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, cùng một thông tin xác thực OAuth phía máy khách sẽ được chuyển cho 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ọ.

Các 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 ID : Được cung cấp nếu luồng id_token được chọn.
  • thông báo truy cập : Được cung cấp nếu dòng mã được chọn. Lưu ý rằng luồng mã hiện chỉ được hỗ trợ qua API REST.
  • Làm mới mã thông báo : Được cung cấp nếu phạm vi offline_access được chọn.

Thí 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 ID
  • Truy cập thẻ
  • Làm mới mã thông báo : 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 trước đó người dùng đã đồng ý và không có phạm vi mới nào được yêu cầu

Thí 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 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ả lại có thể được đổ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, các thông tin đăng nhập sau sẽ được chuyển:

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

Thí 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, các thông tin đăng nhập sau sẽ được chuyển mà không có bất kỳ thông 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, các thông tin đăng nhập sau sẽ được chuyển mà không có bất kỳ thông 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 hàm chặn:

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

Ví dụ sau cho thấy 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 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 là đã được xác minh

Ví dụ sau đây cho thấy cách xử lý email của người dùng từ các 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ừ các đị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 nó 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ụ: các 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 bằng:

    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 của người dùng

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

Truy cập thông tin đăng nhập OAuth của nhà cung cấp danh tính của người dùng

Ví dụ sau 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ã này để gọi các API Lịch Google. Mã 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();
          });
      });
    })
  }
});
,

Nếu bạn đã nâng cấp lên Xác thực Firebase bằng Nền tảng nhận dạng , bạn có thể mở rộng Xác thực Firebase bằng cách chặn các Chức năng đám mây .

Chức năng chặn cho phép bạn thực thi mã tùy chỉnh 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ả lại cho ứ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 làm như vậy trước.

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

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

  • beforeSignIn : Kích hoạt sau khi thông tin đăng nhập của người dùng được xác minh, nhưng trước khi Xác thực Firebase trả về 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 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 các 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à hoạt động ứng dụng không thành công.

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

  • Các chức năng áp dụng cho tất cả người dùng trong dự án của bạn, bao gồm bất kỳ người dùng nào 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 bất kỳ người thuê nào mà họ thuộc về, vì vậy bạn có thể trả lời phù hợp.

  • Việc liên kết nhà cung cấp danh tính khác với 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 các chức năng chặn.

Triển khai và đăng ký một chức năng chặn

Để chèn mã tùy chỉnh của bạn vào quy trình xác thực người dùng, hãy triển khai và đăng ký các chức năng chặn. Sau khi các chức năng chặn của bạn được triển khai và đăng ký, 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.

Triển khai một chức năng chặn

Bạn triển khai một 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 chức năng đám mây để biết thêm 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 các 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 khi cập nhật chúng.

Đăng ký chức năng chặn

  1. Truy cập trang Cài đặt xác thực Firebase trong bảng điều khiển Firebase.

  2. Chọn tab Chức năng chặn .

  3. Đăng ký chức năng chặn của bạn bằng cách chọn nó từ menu thả xuống trong Trước khi tạo tài khoản (beforeCreate) hoặc Trước khi đăng nhập (beforeSignIn) .

  4. Lưu các thay đổi của bạn.

Nhận thông tin về người dùng và ngữ 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. 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 hoạt động 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 tham chiếu API UserRecord .

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

Tên Sự mô tả Thí dụ
locale Ngôn ngữ ứng dụng. Bạn có thể đặt ngôn ngữ bằng cách sử dụng SDK ứng dụng khách hoặc bằng cách chuyể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 chức năng chặn. Mozilla/5.0 (X11; Linux x86_64)
eventId Giá trị nhận dạng 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 USER . USER
resource Đối tượng hoặc dự án 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 đăng nhập của người dùng. AuthCredential

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

Để chặn đăng ký hoặc nỗ lực đăng nhập, hãy HttpsError trong chức năng 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ố Thông điệp
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 trong 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 Tài nguyên được chỉ định không được tìm thấy.
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à khách hàng đã cố gắng tạo đã tồn tại.
resource-exhausted 429 Ngoài hạn ngạch tài nguyên hoặc giới hạn tốc độ đạt đến.
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 dữ liệu bị hỏng.
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 ở trong 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ẽ loại bỏ 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 ra lỗi và xử lý nó cho 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 đăng ký hoặc nỗ lực đăng nhập, bạn có thể cho phép hoạt động 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à trả lại cho 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ủa bạn có chứa các trường để 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 Firebase Authentication, có nghĩa là chúng được đưa vào mã 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 thực thi sau beforeCreate . Các trường người dùng được cập nhật trong beforeCreate được hiển thị trong beforeSignIn . Nếu bạn đặt một trường không phải là sessionClaims trong cả hai trình xử lý sự kiện, giá trị được đặt trong beforeSignIn ghi đè giá trị được đặt trong beforeCreate . Chỉ đối với 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 tồn tại hoặc được lưu trữ trong cơ sở dữ liệu.

Ví dụ: nếu bất kỳ sessionClaims nào được đặt, beforeSignIn sẽ trả về chúng cùng với bất kỳ yêu cầu nào beforeCreate và chúng sẽ được hợp nhất. Khi chúng được hợp nhất, nếu một khóa sessionClaims khớp với một khóa trong customClaims , thì khóa customClaims phù hợp sẽ được 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 sẽ vẫn còn trong cơ sở dữ liệu cho các yêu cầu trong tương lai.

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

Bạn có thể chuyển dữ liệu và thông tin xác thực OAuth cho các chức năng chặn từ các nhà cung cấp danh tính khác nhau. Bảng sau đây cho thấy 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 Tuyên bố đă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ã làm mới trong một 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.

Mã làm mới sẽ không được trả lại bởi bất kỳ nhà cung cấp danh tính nào 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, cùng một thông tin xác thực OAuth phía máy khách sẽ được chuyển cho 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ọ.

Các 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 ID : Được cung cấp nếu luồng id_token được chọn.
  • thông báo truy cập : Được cung cấp nếu dòng mã được chọn. Lưu ý rằng luồng mã hiện chỉ được hỗ trợ qua API REST.
  • Làm mới mã thông báo : Được cung cấp nếu phạm vi offline_access được chọn.

Thí 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 ID
  • Truy cập thẻ
  • Làm mới mã thông báo : 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 trước đó người dùng đã đồng ý và không có phạm vi mới nào được yêu cầu

Thí 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 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ả lại có thể được đổ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, các thông tin đăng nhập sau sẽ được chuyển:

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

Thí 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, các thông tin đăng nhập sau sẽ được chuyển mà không có bất kỳ thông 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, các thông tin đăng nhập sau sẽ được chuyển mà không có bất kỳ thông 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 hàm chặn:

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

Ví dụ sau cho thấy 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 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 là đã được xác minh

Ví dụ sau đây cho thấy cách xử lý email của người dùng từ các 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ừ các đị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 nó 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ụ: các 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 bằng:

    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 của người dùng

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

Truy cập thông tin đăng nhập OAuth của nhà cung cấp danh tính của người dùng

Ví dụ sau 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ã này để gọi các API Lịch Google. Mã 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();
          });
      });
    })
  }
});