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ạtbeforeSignIn
, ngoàibeforeCreate
.
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:
Viết các Hàm đám mây xử lý sự kiện
beforeCreate
, sự kiệnbeforeSignIn
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ể.
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
Truy cập trang Cài đặt xác thực Firebase trong bảng điều khiển Firebase.
Chọn tab Chức năng chặn .
Đă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) .
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 beforeSignIn
và beforeCreate
cung cấp các đối tượng User
và EventContext
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ả beforeCreate
và beforeSignIn
, 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 |
---|---|---|---|---|---|---|
Đúng | Đúng | Đúng | Không | Đúng | Không | |
Không | Đúng | Đúng | Không | Không | Không | |
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 |
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. - Mã 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);
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 .
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
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.
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, }, }; });
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ạtbeforeSignIn
, ngoàibeforeCreate
.
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:
Viết các Hàm đám mây xử lý sự kiện
beforeCreate
, sự kiệnbeforeSignIn
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ể.
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
Truy cập trang Cài đặt xác thực Firebase trong bảng điều khiển Firebase.
Chọn tab Chức năng chặn .
Đă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) .
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 beforeSignIn
và beforeCreate
cung cấp các đối tượng User
và EventContext
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ả beforeCreate
và beforeSignIn
, 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 |
---|---|---|---|---|---|---|
Đúng | Đúng | Đúng | Không | Đúng | Không | |
Không | Đúng | Đúng | Không | Không | Không | |
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 |
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. - Mã 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);
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 .
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
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.
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, }, }; });
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();
});
});
})
}
});