Fungsi pemblokiran dapat Anda gunakan untuk mengeksekusi kode kustom yang mengubah hasil pendaftaran atau login pengguna ke aplikasi Anda. Misalnya, Anda dapat mencegah pengguna melakukan autentikasi jika tidak memenuhi kriteria tertentu, atau memperbarui informasi pengguna sebelum menampilkannya ke aplikasi klien.
Sebelum memulai
Untuk menggunakan fungsi pemblokiran, Anda harus mengupgrade project Firebase ke Firebase Authentication with Identity Platform. Jika Anda belum mengupgradenya, lakukan hal tersebut terlebih dahulu.
Memahami fungsi pemblokiran
Anda dapat mendaftarkan fungsi pemblokiran untuk peristiwa ini:
Sebelum pengguna dibuat: Fungsi pemblokiran terpicu sebelum pengguna baru disimpan ke database Firebase Authentication, dan sebelum token ditampilkan ke aplikasi klien.
Sebelum pengguna login: Fungsi pemblokiran terpicu setelah kredensial pengguna diverifikasi, tetapi sebelum Firebase Authentication menampilkan token ID ke aplikasi klien Anda. Jika aplikasi Anda menggunakan autentikasi multi-faktor, fungsi ini akan terpicu setelah pengguna memverifikasi faktor kedua. Perlu diperhatikan bahwa membuat pengguna baru juga akan memicu kedua peristiwa ini.
Sebelum mengirim email (khusus Node.js): Fungsi pemblokiran terpicu sebelum email (misalnya,
email login atau reset sandi) dikirimkan ke pengguna.Sebelum mengirim pesan SMS (khusus Node.js): Fungsi pemblokiran terpicu sebelum Pesan SMS dikirimkan ke pengguna, untuk kasus seperti autentikasi multi-faktor.
Perhatikan hal-hal berikut saat menggunakan fungsi pemblokiran:
Fungsi Anda harus merespons dalam 7 detik. Setelah 7 detik, Firebase Authentication akan menampilkan error, dan operasi klien gagal.
Kode respons HTTP selain
200
akan diteruskan ke aplikasi klien Anda. Pastikan kode klien menangani error yang dapat ditampilkan fungsi Anda.Fungsi berlaku untuk semua pengguna dalam project Anda, termasuk yang terdapat dalam tenant. Firebase Authentication memberikan informasi tentang pengguna kepada fungsi Anda, termasuk tenant pengguna tersebut, sehingga Anda dapat merespons dengan semestinya.
Menautkan penyedia identitas lain ke akun akan memicu kembali semua fungsi
beforeUserSignedIn
yang terdaftar.Autentikasi kustom dan anonim tidak memicu fungsi pemblokiran.
Men-deploy fungsi pemblokiran
Untuk menyisipkan kode kustom ke dalam alur autentikasi pengguna, deploy fungsi pemblokiran. Setelah fungsi pemblokiran di-deploy, kode kustom Anda harus berhasil diselesaikan agar autentikasi dan pembuatan pengguna berhasil.
Anda men-deploy fungsi pemblokiran dengan cara yang sama seperti men-deploy fungsi apa pun. (lihat halaman Memulai Cloud Functions untuk mengetahui detailnya). Rangkuman:
Menulis fungsi yang menangani peristiwa yang ditargetkan.
Misalnya, untuk memulai, Anda dapat menambahkan fungsi tanpa pengoperasian seperti berikut ke sumber:
Node.js
import { beforeUserCreated, } from "firebase-functions/v2/identity"; export const beforecreated = beforeUserCreated((event) => { // TODO return; });
Python
@identity_fn.before_user_created() def created_noop(event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None: return
Contoh di atas tidak lagi menerapkan logika autentikasi kustom. Lihat bagian berikut untuk mempelajari cara menerapkan fungsi pemblokiran Anda dan Skenario umum untuk contoh tertentu.
Deploy fungsi Anda menggunakan Firebase CLI:
firebase deploy --only functions
Anda harus men-deploy ulang fungsi setiap kali mengupdatenya.
Mendapatkan informasi pengguna dan konteks
Peristiwa pemblokiran menyediakan objek
AuthBlockingEvent
yang berisi informasi tentang proses login pengguna. Gunakan nilai ini dalam kode Anda untuk menentukan apakah akan mengizinkan operasi dilanjutkan atau tidak.
Objek berisi properti berikut:
Nama | Deskripsi | Contoh |
---|---|---|
locale |
Lokalitas aplikasi. Anda dapat menetapkan lokalitas menggunakan SDK klien, atau dengan meneruskan header lokalitas di REST API. | fr atau sv-SE |
ipAddress
| Alamat IP perangkat tempat pengguna akhir mendaftar atau login. | 114.14.200.1 |
userAgent
| Agen pengguna yang memicu fungsi pemblokiran. | Mozilla/5.0 (X11; Linux x86_64) |
eventId
| ID unik peristiwa. | rWsyPtolplG2TBFoOkkgyg |
eventType
|
Jenis peristiwa. Properti ini memberikan informasi tentang nama peristiwa, seperti beforeSignIn atau beforeCreate , dan metode login terkait yang digunakan, seperti Google atau email/sandi.
|
providers/cloud.auth/eventTypes/user.beforeSignIn:password
|
authType
| Selalu USER . |
USER
|
resource
| Project atau tenant Firebase Authentication. |
projects/project-id/tenants/tenant-id
|
timestamp
| Waktu peristiwa dipicu, yang diformat sebagai string RFC 3339. | Tue, 23 Jul 2019 21:10:57 GMT
|
additionalUserInfo
| Objek yang berisi informasi tentang pengguna. |
AdditionalUserInfo
|
credential
| Objek yang berisi informasi tentang kredensial pengguna. |
AuthCredential
|
Memblokir pendaftaran atau login
Untuk memblokir upaya pendaftaran atau login, tampilkan HttpsError
dalam fungsi Anda. Contoh:
Node.js
import { HttpsError } from "firebase-functions/v2/identity";
throw new HttpsError('invalid-argument');
Python
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT)
Anda juga dapat menentukan pesan error kustom:
Node.js
throw new HttpsError('permission-denied', 'Unauthorized request origin!');
Python (pratinjau)
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.PERMISSION_DENIED,
message="Unauthorized request origin!"
)
Contoh berikut menunjukkan cara memblokir pengguna yang berada di luar domain tertentu agar tidak mendaftar ke aplikasi Anda:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
// (If the user is authenticating within a tenant context, the tenant ID can be determined from
// user.tenantId or from event.resource, e.g. 'projects/project-id/tenant/tenant-id-1')
// Only users of a specific domain can sign up.
if (!user?.email?.includes('@acme.com')) {
throw new HttpsError('invalid-argument', "Unauthorized email");
}
});
Python
# Block account creation with any non-acme email address.
@identity_fn.before_user_created()
def validatenewuser(
event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None:
# User data passed in from the CloudEvent.
user = event.data
# Only users of a specific domain can sign up.
if user.email is None or "@acme.com" not in user.email:
# Return None so that Firebase Auth rejects the account creation.
raise https_fn.HttpsError(code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
message="Unauthorized email")
Terlepas dari apakah Anda menggunakan pesan default atau kustom, Cloud Functions menggabungkan error dan menampilkannya ke klien sebagai error internal. Contoh:
Node.js
throw new HttpsError('invalid-argument', "Unauthorized email");
Python
# Only users of a specific domain can sign up.
if user.email is None or "@acme.com" not in user.email:
# Return None so that Firebase Auth rejects the account creation.
raise https_fn.HttpsError(code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
message="Unauthorized email")
Aplikasi Anda harus menangkap error tersebut, dan menanganinya secara semestinya. Contoh:
JavaScript
import { getAuth, createUserWithEmailAndPassword } from 'firebase/auth';
// Blocking functions can also be triggered in a multi-tenant context before user creation.
// firebase.auth().tenantId = 'tenant-id-1';
const auth = getAuth();
try {
const result = await createUserWithEmailAndPassword(auth)
const idTokenResult = await result.user.getIdTokenResult();
console.log(idTokenResult.claim.admin);
} catch(error) {
if (error.code !== 'auth/internal-error' && error.message.indexOf('Cloud Function') !== -1) {
// Display error.
} else {
// Registration succeeds.
}
}
Mengubah pengguna
Daripada memblokir upaya pendaftaran atau login, Anda dapat mengizinkan
operasi untuk dilanjutkan, tetapi mengubah objek User
yang disimpan ke
database Firebase Authentication dan ditampilkan ke klien.
Untuk mengubah pengguna, tampilkan objek dari pengendali peristiwa yang berisi kolom yang akan diubah. Anda dapat mengubah kolom berikut:
displayName
disabled
emailVerified
photoUrl
customClaims
sessionClaims
(beforeUserSignedIn
saja)
Dengan pengecualian sessionClaims
, semua kolom yang diubah disimpan ke
database Firebase Authentication, yang berarti kolom tersebut disertakan pada token
respons dan terus dipertahankan di antara sesi pengguna.
Contoh berikut menunjukkan cara menetapkan nama tampilan default:
Node.js
export const beforecreated = beforeUserCreated((event) => {
return {
// If no display name is provided, set it to "Guest".
displayName: event.data.displayName || 'Guest'
};
});
Python
@identity_fn.before_user_created()
def setdefaultname(event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None:
return identity_fn.BeforeCreateResponse(
# If no display name is provided, set it to "Guest".
display_name=event.data.display_name if event.data.display_name is not None else "Guest")
Jika Anda mendaftarkan pengendali peristiwa untuk beforeUserCreated
dan beforeUserSignedIn
,
perhatikan bahwa beforeUserSignedIn
dijalankan setelah beforeUserCreated
. Kolom pengguna yang diperbarui di beforeUserCreated
dapat dilihat di beforeUserSignedIn
. Jika Anda menetapkan kolom selain sessionClaims
di kedua pengendali peristiwa, nilai yang ditetapkan dalam beforeUserSignedIn
akan menimpa nilai yang ditetapkan dalam beforeUserCreated
. Khusus untuk sessionClaims
, kolom tersebut diterapkan ke klaim token sesi saat ini, tetapi tidak dipertahankan atau disimpan dalam database.
Misalnya, jika sessionClaims
ditetapkan, beforeUserSignedIn
akan menampilkannya dengan klaim beforeUserCreated
, dan keduanya akan digabungkan. Saat digabungkan, jika kunci sessionClaims
cocok dengan kunci di customClaims
, customClaims
yang cocok akan ditimpa dalam klaim token oleh kunci sessionClaims
. Namun, kunci customClaims
yang ditimpa akan tetap dipertahankan dalam database untuk permintaan berikutnya.
Kredensial dan data OAuth yang didukung
Anda dapat meneruskan kredensial dan data OAuth ke fungsi pemblokiran dari berbagai penyedia identitas. Tabel berikut menunjukkan kredensial dan data yang didukung untuk setiap penyedia identitas:
Penyedia Identitas | Token ID | Token Akses | Waktu Kedaluwarsa | Secret Token | Token Refresh | Klaim Login |
---|---|---|---|---|---|---|
Ya | Ya | Ya | Tidak | Ya | Tidak | |
Tidak | Ya | Ya | Tidak | Tidak | Tidak | |
Tidak | Ya | Tidak | Ya | Tidak | Tidak | |
GitHub | Tidak | Ya | Tidak | Tidak | Tidak | Tidak |
Microsoft | Ya | Ya | Ya | Tidak | Ya | Tidak |
Tidak | Ya | Ya | Tidak | Tidak | Tidak | |
Yahoo | Ya | Ya | Ya | Tidak | Ya | Tidak |
Apple | Ya | Ya | Ya | Tidak | Ya | Tidak |
SAML | Tidak | Tidak | Tidak | Tidak | Tidak | Ya |
OIDC | Ya | Ya | Ya | Tidak | Ya | Ya |
Token OAuth
Untuk menggunakan token ID, token akses, atau token refresh dalam fungsi pemblokiran, Anda harus terlebih dahulu mencentang kotak di halaman Blocking functions pada Firebase console.
Token refresh tidak akan ditampilkan oleh penyedia identitas mana pun saat login secara langsung dengan kredensial OAuth, seperti token ID atau token akses. Dalam situasi ini, kredensial OAuth sisi klien yang sama akan diteruskan ke fungsi pemblokiran.
Bagian berikut menjelaskan setiap jenis penyedia identitas serta kredensial dan datanya yang didukung.
Penyedia OIDC umum
Saat pengguna login dengan penyedia OIDC umum, kredensial berikut akan diteruskan:
- Token ID: Diberikan jika alur
id_token
dipilih. - Token akses: Diberikan jika alur kode dipilih. Perlu diperhatikan bahwa alur kode saat ini hanya didukung melalui REST API.
- Token refresh: Diberikan jika cakupan
offline_access
dipilih.
Contoh:
const provider = new firebase.auth.OAuthProvider('oidc.my-provider');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);
Saat pengguna login dengan Google, kredensial berikut akan diteruskan:
- Token ID
- Token akses
- Token refresh: Hanya diberikan jika parameter kustom berikut diminta:
access_type=offline
prompt=consent
, jika sebelumnya pengguna telah memberikan izin dan tidak ada cakupan baru yang diminta
Contoh:
import { getAuth, signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
const auth = getAuth();
const provider = new GoogleAuthProvider();
provider.setCustomParameters({
'access_type': 'offline',
'prompt': 'consent'
});
signInWithPopup(auth, provider);
Pelajari token refresh Google lebih lanjut.
Saat pengguna login dengan Facebook, kredensial berikut akan diteruskan:
- Token akses: Token akses ditampilkan, yang dapat ditukar dengan token akses lain. Pelajari lebih lanjut berbagai jenis token akses yang didukung oleh Facebook dan cara menukarnya dengan token dengan masa berlaku yang lama.
GitHub
Saat pengguna login dengan GitHub, kredensial berikut akan diteruskan:
- Token akses: Masa berlakunya tidak pernah berakhir kecuali jika dicabut.
Microsoft
Saat pengguna login dengan Microsoft, kredensial berikut akan diteruskan:
- Token ID
- Token akses
- Token refresh: Diteruskan ke fungsi pemblokiran jika cakupan
offline_access
dipilih.
Contoh:
import { getAuth, signInWithPopup, OAuthProvider } from 'firebase/auth';
const auth = getAuth();
const provider = new OAuthProvider('microsoft.com');
provider.addScope('offline_access');
signInWithPopup(auth, provider);
Yahoo
Saat pengguna login dengan Yahoo, kredensial berikut akan diteruskan tanpa cakupan atau parameter kustom apa pun:
- Token ID
- Token akses
- Token refresh
Saat pengguna login dengan LinkedIn, kredensial berikut akan diteruskan:
- Token akses
Apple
Saat pengguna login dengan Apple, kredensial berikut akan diteruskan tanpa cakupan atau parameter kustom apa pun:
- Token ID
- Token akses
- Token refresh
Skenario umum
Contoh berikut menunjukkan beberapa kasus penggunaan umum untuk fungsi pemblokiran:
Hanya mengizinkan pendaftaran dari domain tertentu
Contoh berikut menunjukkan cara mencegah pengguna yang bukan bagian dari domain example.com
mendaftar ke aplikasi Anda:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
if (!user?.email?.includes('@example.com')) {
throw new HttpsError(
'invalid-argument', 'Unauthorized email');
}
});
Python (pratinjau)
@identity_fn.before_user_created()
def validatenewuser(
event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
# User data passed in from the CloudEvent.
user = event.data
# Only users of a specific domain can sign up.
if user.email is None or "@example.com" not in user.email:
# Return None so that Firebase Auth rejects the account creation.
raise https_fn.HttpsError(
code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
message="Unauthorized email",
)
Memblokir pengguna dengan email yang belum diverifikasi agar tidak mendaftar
Contoh berikut menunjukkan cara mencegah pengguna dengan email yang belum diverifikasi agar tidak mendaftar ke aplikasi Anda:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
if (user.email && !user.emailVerified) {
throw new HttpsError(
'invalid-argument', 'Unverified email');
}
});
Python
@identity_fn.before_user_created()
def requireverified(
event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None:
if event.data.email is not None and not event.data.email_verified:
raise https_fn.HttpsError(code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
message="You must register using a trusted provider.")
Memperlakukan email penyedia identitas tertentu sebagai terverifikasi
Contoh berikut menunjukkan cara memperlakukan email pengguna dari penyedia identitas tertentu sebagai terverifikasi:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
if (user.email && !user.emailVerified && event.eventType.includes(':facebook.com')) {
return {
emailVerified: true,
};
}
});
Python
@identity_fn.before_user_created()
def markverified(event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None:
if event.data.email is not None and "@facebook.com" in event.data.email:
return identity_fn.BeforeSignInResponse(email_verified=True)
Memblokir login dari alamat IP tertentu
Contoh berikut menunjukkan cara memblokir login dari rentang alamat IP tertentu:
Node.js
export const beforesignedin = beforeUserSignedIn((event) => {
if (isSuspiciousIpAddress(event.ipAddress)) {
throw new HttpsError(
'permission-denied', 'Unauthorized access!');
}
});
Python
@identity_fn.before_user_signed_in()
def ipban(event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeSignInResponse | None:
if is_suspicious(event.ip_address):
raise https_fn.HttpsError(code=https_fn.FunctionsErrorCode.PERMISSION_DENIED,
message="IP banned.")
Menetapkan klaim kustom dan sesi
Contoh berikut menunjukkan cara menetapkan klaim kustom dan sesi:
Node.js
export const beforecreated = beforeUserCreated((event) => {
if (event.credential &&
event.credential.claims &&
event.credential.providerId === "saml.my-provider-id") {
return {
// Employee ID does not change so save in persistent claims (stored in
// Auth DB).
customClaims: {
eid: event.credential.claims.employeeid,
},
};
}
});
export const beforesignin = beforeUserSignedIn((event) => {
if (event.credential &&
event.credential.claims &&
event.credential.providerId === "saml.my-provider-id") {
return {
// Copy role and groups to token claims. These will not be persisted.
sessionClaims: {
role: event.credential.claims.role,
groups: event.credential.claims.groups,
},
};
}
});
Python
@identity_fn.before_user_created()
def setemployeeid(event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None:
if (event.credential is not None and event.credential.claims is not None and
event.credential.provider_id == "saml.my-provider-id"):
return identity_fn.BeforeCreateResponse(
custom_claims={"eid": event.credential.claims["employeeid"]})
@identity_fn.before_user_signed_in()
def copyclaimstosession(
event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeSignInResponse | None:
if (event.credential is not None and event.credential.claims is not None and
event.credential.provider_id == "saml.my-provider-id"):
return identity_fn.BeforeSignInResponse(session_claims={
"role": event.credential.claims["role"],
"groups": event.credential.claims["groups"]
})
Melacak alamat IP untuk memantau aktivitas yang mencurigakan
Anda dapat mencegah pencurian token dengan melacak alamat IP yang digunakan pengguna untuk login, lalu membandingkannya dengan alamat IP pada permintaan berikutnya. Jika permintaan tersebut tampak mencurigakan — misalnya, IP berasal dari wilayah geografis yang berbeda — Anda dapat meminta pengguna untuk login lagi.
Gunakan klaim sesi untuk melacak alamat IP yang digunakan pengguna untuk login:
Node.js
export const beforesignedin = beforeUserSignedIn((event) => { return { sessionClaims: { signInIpAddress: event.ipAddress, }, }; });
Python
@identity_fn.before_user_signed_in() def logip(event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeSignInResponse | None: return identity_fn.BeforeSignInResponse(session_claims={"signInIpAddress": event.ip_address})
Saat pengguna mencoba mengakses resource yang memerlukan autentikasi dengan Firebase Authentication, bandingkan alamat IP dalam permintaan dengan IP yang digunakan untuk login:
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!' }) }); } }); });
Python (pratinjau)
from firebase_admin import auth, initialize_app import flask initialize_app() flask_app = flask.Flask(__name__) @flask_app.post() def get_restricted_data(req: flask.Request): # Get the ID token passed. id_token = req.json().get("idToken") # Verify the ID token, check if revoked, and decode its payload. try: claims = auth.verify_id_token(id_token, check_revoked=True) except: return flask.Response(status=500) # Get request IP address. request_ip = req.remote_addr # Get sign-in IP address. signin_ip = claims["signInIpAddress"] # Check if the request IP address origin is suspicious relative to # the session IP addresses. The current request timestamp and the # auth_time of the ID token can provide additional signals of abuse, # especially if the IP address suddenly changed. If there was a sudden # geographical change in a short period of time, then it will give # stronger signals of possible abuse. if is_suspicious_change(signin_ip, request_ip): # Suspicious IP address change. Require re-authentication. # You can also revoke all user sessions by calling: # auth.revoke_refresh_tokens(claims["sub"]) return flask.Response(status=401, response="Unauthorized access. Sign in again!") else: # Access is valid. Try to return data. return data_from_claims(claims)
Menyeleksi foto pengguna
Contoh berikut menunjukkan cara membersihkan foto profil pengguna:
Node.js
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
if (user.photoURL) {
return isPhotoAppropriate(user.photoURL)
.then((status) => {
if (!status) {
// Sanitize inappropriate photos by replacing them with guest photos.
// Users could also be blocked from sign-up, disabled, etc.
return {
photoUrl: PLACEHOLDER_GUEST_PHOTO_URL,
};
}
});
});
Python
@identity_fn.before_user_created()
def sanitizeprofilephoto(
event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None:
if event.data.photo_url is not None:
score = analyze_photo_with_ml(event.data.photo_url)
if score > THRESHOLD:
return identity_fn.BeforeCreateResponse(photo_url=PLACEHOLDER_URL)
Untuk mempelajari cara mendeteksi dan membersihkan gambar lebih lanjut, lihat dokumentasi Cloud Vision.
Mengakses kredensial OAuth penyedia identitas pengguna
Contoh berikut menunjukkan cara mendapatkan token refresh untuk pengguna yang login dengan Google, dan menggunakannya untuk memanggil API Google Kalender. Token refresh disimpan untuk akses offline.
Node.js
const {OAuth2Client} = require('google-auth-library');
const {google} = require('googleapis');
// ...
// Initialize Google OAuth client.
const keys = require('./oauth2.keys.json');
const oAuth2Client = new OAuth2Client(
keys.web.client_id,
keys.web.client_secret
);
export const beforecreated = beforeUserCreated((event) => {
const user = event.data;
if (event.credential &&
event.credential.providerId === 'google.com') {
// Store the refresh token for later offline use.
// These will only be returned if refresh tokens credentials are included
// (enabled by Cloud console).
return saveUserRefreshToken(
user.uid,
event.credential.refreshToken,
'google.com'
)
.then(() => {
// Blocking the function is not required. The function can resolve while
// this operation continues to run in the background.
return new Promise((resolve, reject) => {
// For this operation to succeed, the appropriate OAuth scope should be requested
// on sign in with Google, client-side. In this case:
// https://www.googleapis.com/auth/calendar
// You can check granted_scopes from within:
// event.additionalUserInfo.profile.granted_scopes (space joined list of scopes).
// Set access token/refresh token.
oAuth2Client.setCredentials({
access_token: event.credential.accessToken,
refresh_token: event.credential.refreshToken,
});
const calendar = google.calendar('v3');
// Setup Onboarding event on user's calendar.
const event = {/** ... */};
calendar.events.insert({
auth: oauth2client,
calendarId: 'primary',
resource: event,
}, (err, event) => {
// Do not fail. This is a best effort approach.
resolve();
});
});
})
}
});
Python
@identity_fn.before_user_created()
def savegoogletoken(
event: identity_fn.AuthBlockingEvent) -> identity_fn.BeforeCreateResponse | None:
"""During sign-up, save the Google OAuth2 access token and queue up a task
to schedule an onboarding session on the user's Google Calendar.
You will only get an access token if you enabled it in your project's blocking
functions settings in the Firebase console:
https://console.firebase.google.com/project/_/authentication/settings
"""
if event.credential is not None and event.credential.provider_id == "google.com":
print(f"Signed in with {event.credential.provider_id}. Saving access token.")
firestore_client: google.cloud.firestore.Client = firestore.client()
doc_ref = firestore_client.collection("user_info").document(event.data.uid)
doc_ref.set({"calendar_access_token": event.credential.access_token}, merge=True)
tasks_client = google.cloud.tasks_v2.CloudTasksClient()
task_queue = tasks_client.queue_path(params.PROJECT_ID.value,
options.SupportedRegion.US_CENTRAL1,
"scheduleonboarding")
target_uri = get_function_url("scheduleonboarding")
calendar_task = google.cloud.tasks_v2.Task(http_request={
"http_method": google.cloud.tasks_v2.HttpMethod.POST,
"url": target_uri,
"headers": {
"Content-type": "application/json"
},
"body": json.dumps({
"data": {
"uid": event.data.uid
}
}).encode()
},
schedule_time=datetime.now() +
timedelta(minutes=1))
tasks_client.create_task(parent=task_queue, task=calendar_task)
Mengganti putusan reCAPTCHA Enterprise untuk operasi pengguna
Contoh berikut menunjukkan cara mengganti putusan reCAPTCHA Enterprise untuk alur penggunaan yang didukung.
Lihat Mengaktifkan reCAPTCHA Enterprise untuk mempelajari lebih lanjut cara mengintegrasikan reCAPTCHA Enterprise dengan Firebase Authentication.
Fungsi pemblokiran dapat digunakan untuk mengizinkan atau memblokir alur berdasarkan faktor kustom, sehingga menggantikan hasil yang diberikan oleh reCAPTCHA Enterprise.
Node.js
const { beforeSmsSent } = require("firebase-functions/v2/identity");
exports.beforesmssentv2 = beforeSmsSent((event) => {
if (
event.smsType === "SIGN_IN_OR_SIGN_UP" &&
event.additionalUserInfo.phoneNumber.includes('+91')
) {
return {
recaptchaActionOverride: "ALLOW",
};
}
// Allow users to sign in with recaptcha score greater than 0.5
if (event.additionalUserInfo.recaptchaScore > 0.5) {
return {
recaptchaActionOverride: 'ALLOW',
};
}
// Block all others.
return {
recaptchaActionOverride: 'BLOCK',
}
});