1. Başlamadan önce
Web uygulamanızla etkileşimde bulunan kullanıcıların meşruiyetini sağlamak için Firebase Uygulama Kontrolü'nü uygulayacak ve kullanıcı oturumlarını doğrulamak için reCAPTCHA JWT jetonlarından yararlanacaksınız. Bu kurulum, istemci uygulamasından Places API (Yeni)'ye gelen istekleri güvenli bir şekilde işlemenizi sağlar.

Ne oluşturacaksınız?
Bunu göstermek için, yüklendiğinde harita görüntüleyen bir web uygulaması oluşturacaksınız. Ayrıca Firebase SDK'sını kullanarak gizlice bir reCAPTCHA jetonu oluşturur. Bu jeton daha sonra Node.js sunucunuza gönderilir. Firebase, Places API'ye yapılan istekleri yerine getirmeden önce bu jetonu doğrular.
Jeton geçerliyse Firebase Uygulama Kontrolü, jetonun süresi dolana kadar saklar. Böylece her istemci isteği için yeni bir jeton oluşturulması gerekmez. Jeton geçersizse kullanıcıdan yeni bir jeton almak için reCAPTCHA doğrulamasını tekrar tamamlaması istenir.
2. Ön koşullar
Bu Codelab'i tamamlamak için aşağıdaki öğeler hakkında bilgi edinmeniz gerekir. 
Gerekli Google Cloud Ürünleri
- Google Cloud Firebase Uygulama Kontrolü: Jeton yönetimi için veritabanı
- Google reCAPTCHA: jeton oluşturma ve doğrulama. Web sitelerinde insanları botlardan ayırt etmek için kullanılan bir araçtır. Kullanıcı davranışını, tarayıcı özelliklerini ve ağ bilgilerini analiz ederek kullanıcının bot olma olasılığını gösteren bir puan oluşturur. Puan yeterince yüksekse kullanıcı insan olarak kabul edilir ve başka bir işlem yapılması gerekmez. Puan düşükse kullanıcının kimliğini doğrulamak için CAPTCHA bulmacası gösterilebilir. Bu yaklaşım, geleneksel CAPTCHA yöntemlerine göre daha az rahatsız edicidir ve kullanıcı deneyimini daha sorunsuz hale getirir.
- (İsteğe bağlı) Google Cloud App Engine: dağıtım ortamı.
Zorunlu Google Haritalar Platformu Ürünleri
Bu Codelab'de aşağıdaki Google Haritalar Platformu ürünlerini kullanacaksınız:
- Web uygulamasında Maps JavaScript API'nin yüklenmesi ve gösterilmesi
- Arka uç sunucusu tarafından verilen Places API (Yeni) isteği
Bu Codelab'in Diğer Koşulları
Bu Codelab'i tamamlamak için aşağıdaki hesaplara, hizmetlere ve araçlara ihtiyacınız vardır:
- Faturalandırmanın etkin olduğu bir Google Cloud Platform hesabı
- Maps JavaScript API ve Yerler etkinleştirilmiş bir Google Haritalar Platformu API anahtarı
- JavaScript, HTML ve CSS hakkında temel bilgi
- Node.js hakkında temel bilgiler
- Seçtiğiniz bir metin düzenleyici veya IDE
3. Hazırlanın
Google Haritalar Platformu'nu ayarlama
Henüz bir Google Cloud Platform hesabınız ve faturalandırmanın etkinleştirildiği bir projeniz yoksa lütfen faturalandırma hesabı ve proje oluşturmak için Google Haritalar Platformu'nu Kullanmaya Başlama kılavuzuna bakın.
- Cloud Console'da proje açılır menüsünü tıklayın ve bu codelab için kullanmak istediğiniz projeyi seçin.

- Bu codelab için gereken Google Haritalar Platformu API'lerini ve SDK'larını Google Cloud Marketplace'te etkinleştirin. Bunun için bu videodaki veya bu dokümandaki adımları uygulayın.
- Cloud Console'un Kimlik Bilgileri sayfasında bir API anahtarı oluşturun. Bu videodaki veya bu dokümandaki adımları uygulayabilirsiniz. Google Haritalar Platformu'na yapılan tüm istekler için API anahtarı gerekir.
Uygulama Varsayılan Kimlik Bilgileri
Firebase projenizle etkileşim kurmak ve Places API'ye istekte bulunmak için Firebase Admin SDK'yı kullanırsınız. Bu SDK'nın çalışması için geçerli kimlik bilgileri sağlamanız gerekir.
Sunucunuzun istekte bulunabilmesi için kimliğini doğrulamak üzere ADC kimlik doğrulama (otomatik varsayılan kimlik bilgileri) kullanılır. Alternatif olarak (önerilmez) bir hizmet hesabı oluşturabilir ve kimlik bilgilerini kodunuzda saklayabilirsiniz.
Tanım: Uygulama Varsayılan Kimlik Bilgileri (ADC), Google Cloud'un kimlik bilgilerini açıkça yönetmeden uygulamalarınızın kimliğini otomatik olarak doğrulamak için sağladığı bir mekanizmadır. Çeşitli konumlarda (ör. ortam değişkenleri, hizmet hesabı dosyaları veya Google Cloud meta veri sunucusu) kimlik bilgilerini arar ve bulduğu ilk kimlik bilgisini kullanır.
- Terminalinizde, uygulamalarınızın şu anda oturum açmış kullanıcı adına Google Cloud kaynaklarına güvenli bir şekilde erişmesine olanak tanıyan aşağıdaki komutu kullanın:
gcloud auth application-default login
- Kök dizinde, Google Cloud projesi değişkenini belirten bir .env dosyası oluşturacaksınız:
GOOGLE_CLOUD_PROJECT="your-project-id"
Alternatif Kimlik Bilgileri (Önerilmez)
Hizmet hesabı oluşturma
- Google Haritalar Platformu sekmesi > "+Kimlik bilgisi oluştur" > Hizmet hesabı
- Firebase AppCheck Yöneticisi rolünü ekleyin, ardından az önce yazdığınız hizmet hesabı adını girin (ör. firebase-appcheck-codelab@yourproject.iam.gserviceaccount.com).
Kimlik bilgileri
- Oluşturulan hizmet hesabını tıklayın.
- Anahtar oluşturmak için ANAHTARLAR sekmesine gidin > JSON > indirilen JSON kimlik bilgilerini kaydedin. Otomatik olarak indirilen xxx.json dosyasını kök klasörünüze taşıyın.
- (Sonraki Bölüm) Dosyayı nodejs dosyasında server.js (firebase-credentials.json) olarak doğru şekilde adlandırın.
4. Firebase App Check entegrasyonu
Firebase yapılandırma ayrıntılarını ve reCAPTCHA gizli anahtarlarını alırsınız.
Bunları demo uygulamasına yapıştırıp sunucuyu başlatacaksınız.
Firebase'de uygulama oluşturma
- Proje yöneticisine https://console.firebase.google.com adresinden gidin (bağlantıları bulun):
Daha önce oluşturulmuş Google Cloud projesini SEÇİN ("Üst kaynağı seçme" işlemini belirtmeniz gerekebilir).

- Sol üstteki menüden (dişli) uygulama ekleme

Firebase başlatma kodu
- İstemci tarafı için script.js dosyasına (sonraki bölüm) yapıştırılacak Firebase başlatma kodunu kaydedin.

- Firebase'in reCAPTCHA s3 jetonlarını kullanmasına izin vermek için uygulamanızı kaydetme
https://console.firebase.google.com/u/0/project/YOUR_PROJECT/appcheck/apps

- reCAPTCHA'yı seçin → reCAPTCHA web sitesinde anahtar oluşturun (doğru alanlar yapılandırılmış olmalıdır: uygulama geliştirme için localhost)

- reCAPTCHA gizli anahtarını Firebase App Check'e yapıştırın

- Uygulama durumu yeşile dönmelidir.

5. Demo uygulaması
- İstemci Web Uygulaması: HTML, JavaScript, CSS dosyaları
- Sunucu: Node.js dosyası
- Ortam (.env): API anahtarları
- Yapılandırma (app.yaml): Google App Engine dağıtım ayarları
Node.js kurulumu:
- Gezinin: Terminalinizi açın ve klonlanmış projenizin kök dizinine gidin.
- Node.js'yi yükleyin (gerekirse): 18 veya daha yeni bir sürüm.
node -v # Check installed version
- Projeyi başlatma: Tüm ayarları varsayılan olarak bırakarak yeni bir Node.js projesini başlatmak için aşağıdaki komutu çalıştırın:
npm init
- Bağımlılıkları Yükleme: Gerekli proje bağımlılıklarını yüklemek için aşağıdaki komutu kullanın:
npm install @googlemaps/places firebase-admin express axios dotenv
Yapılandırma: Google Cloud projesi için ortam değişkenleri
- Ortam Dosyası Oluşturma: Projenizin kök dizininde
.envadlı bir dosya oluşturun. Bu dosya, hassas yapılandırma verilerini depolar ve sürüm denetimine gönderilmemelidir. - Ortam Değişkenlerini Doldurma:
.envdosyasını açın ve yer tutucuları Google Cloud projenizdeki gerçek değerlerle değiştirerek aşağıdaki değişkenleri ekleyin:
# Google Cloud Project ID
GOOGLE_CLOUD_PROJECT="your-cloud-project-id"
# reCAPTCHA Keys (obtained in previous steps)
RECAPTCHA_SITE_KEY="your-recaptcha-site-key"
RECAPTCHA_SECRET_KEY="your-recaptcha-secret-key"
# Maps Platform API Keys (obtained in previous steps)
PLACES_API_KEY="your-places-api-key"
MAPS_API_KEY="your-maps-api-key"
6. Koda genel bakış
index.html
- Uygulamada jeton oluşturmak için Firebase kitaplıklarını yükler.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Places API with AppCheck</title>
<style></style> </head>
<body>
<div id="map"></div>
<!-- Firebase services -->
<script src="https://www.gstatic.com/firebasejs/9.15.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.15.0/firebase-app-check-compat.js"></script>
<script type="module" src="./script.js"></script>
<link rel="stylesheet" href="./style.css">
</body>
</html>
script.js
- API anahtarlarını getirir: Google Haritalar ve Firebase Uygulama Kontrolü için API anahtarlarını bir arka uç sunucusundan alır.
- Firebase'i başlatır: Firebase'i kimlik doğrulama ve güvenlik için ayarlar. (Yapılandırmayı değiştirme → Bölüm 4'e bakın).
Firebase Uygulama Kontrolü jetonunun geçerlilik süresi (30 dakika ile 7 gün arasında) Firebase konsolunda yapılandırılır ve jeton yenileme işlemi zorlanarak değiştirilemez.
- Uygulama Kontrolü'nü etkinleştirir: Gelen isteklerin gerçekliğini doğrulamak için Firebase Uygulama Kontrolü'nü etkinleştirir.
- Google Haritalar API'sini yükler: Haritayı görüntülemek için Google Haritalar JavaScript kitaplığını dinamik olarak yükler.
- Haritayı başlatır: Varsayılan bir konumun ortasında bir Google Haritası oluşturur.
- Harita Tıklamalarını İşler: Haritadaki tıklamaları dinler ve odak noktasını buna göre günceller.
- Places API'ye sorgu gönderir: Yetkilendirme için Firebase Uygulama Kontrolü'nü kullanarak tıklanan konumun yakınındaki yerler (restoranlar, parklar, barlar) hakkında bilgi almak üzere bir arka uç API'sine (
/api/data) istek gönderir. - İşaretçileri Gösterir: Getirilen verileri haritada işaretçi olarak çizer, adlarını ve simgelerini gösterir.
let mapsApiKey, recaptchaKey; // API keys
let currentAppCheckToken = null; // AppCheck token
async function init() {
try {
await fetchConfig(); // Load API keys from .env variable
/////////// REPLACE with your Firebase configuration details
const firebaseConfig = {
apiKey: "AIza.......",
authDomain: "places.......",
projectId: "places.......",
storageBucket: "places.......",
messagingSenderId: "17.......",
appId: "1:175.......",
measurementId: "G-CPQ.......",
};
/////////// REPLACE
// Initialize Firebase and App Check
await firebase.initializeApp(firebaseConfig);
await firebase.appCheck().activate(recaptchaKey);
// Get the initial App Check token
currentAppCheckToken = await firebase.appCheck().getToken();
// Load the Maps JavaScript API dynamically
const scriptMaps = document.createElement("script");
scriptMaps.src = `https://maps.googleapis.com/maps/api/js?key=${mapsApiKey}&libraries=marker,places&v=beta`;
scriptMaps.async = true;
scriptMaps.defer = true;
scriptMaps.onload = initMap; // Create the map after the script loads
document.head.appendChild(scriptMaps);
} catch (error) {
console.error("Firebase initialization error:", error);
// Handle the error appropriately (e.g., display an error message)
}
}
window.onload = init()
// Fetch configuration data from the backend API
async function fetchConfig() {
const url = "/api/config";
try {
const response = await fetch(url);
const config = await response.json();
mapsApiKey = config.mapsApiKey;
recaptchaKey = config.recaptchaKey;
} catch (error) {
console.error("Error fetching configuration:", error);
// Handle the error (e.g., show a user-friendly message)
}
}
// Initialize the map when the Maps API script loads
let map; // Dynamic Map
let center = { lat: 48.85557501, lng: 2.34565006 };
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: center,
zoom: 13,
mapId: "b93f5cef6674c1ff",
zoomControlOptions: {
position: google.maps.ControlPosition.RIGHT_TOP,
},
streetViewControl: false,
mapTypeControl: false,
clickableIcons: false,
fullscreenControlOptions: {
position: google.maps.ControlPosition.LEFT_TOP,
},
});
// Initialize the info window for markers
infoWindow = new google.maps.InfoWindow({});
// Add a click listener to the map
map.addListener("click", async (event) => {
try {
// Get a fresh App Check token on each click
const appCheckToken = await firebase.appCheck().getToken();
currentAppCheckToken = appCheckToken;
// Update the center for the Places API query
center.lat = event.latLng.lat();
center.lng = event.latLng.lng();
// Query for places with the new token and center
queryPlaces();
} catch (error) {
console.error("Error getting App Check token:", error);
}
});
}
function queryPlaces() {
const url = '/api/data'; // "http://localhost:3000/api/data"
const body = {
request: {
includedTypes: ['restaurant', 'park', 'bar'],
excludedTypes: [],
maxResultCount: 20,
locationRestriction: {
circle: {
center: {
latitude: center.lat,
longitude: center.lng,
},
radius: 4000,
},
},
},
};
// Provides token to the backend using header: X-Firebase-AppCheck
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Firebase-AppCheck': currentAppCheckToken.token,
},
body: JSON.stringify(body),
})
.then((response) => response.json())
.then((data) => {
// display if response successful
displayMarkers(data.places);
})
.catch((error) => {
alert('No places');
// eslint-disable-next-line no-console
console.error('Error:', error);
});
}
//// display places markers on map
...
server.js
.envdosyasından ortam değişkenlerini (API anahtarları, Google proje kimliği) yükler.- Sunucuyu başlatır ve
http://localhost:3000üzerindeki istekleri dinler. - Uygulama Varsayılan Kimlik Bilgileri (ADC) kullanılarak Firebase Admin SDK'sı başlatılır.
script.js'dan reCAPTCHA jetonu alır.- Alınan jetonun geçerliliğini doğrular.
- Jeton geçerliyse Google Places API'ye dahil edilen arama parametreleriyle bir POST isteği gönderir.
- Places API'den yanıtı işler ve istemciye döndürür.
const express = require('express');
const axios = require('axios');
const admin = require('firebase-admin');
// .env variables
require('dotenv').config();
// Store sensitive API keys in environment variables
const recaptchaSite = process.env.RECAPTCHA_SITE_KEY;
const recaptchaSecret = process.env.RECAPTCHA_SECRET_KEY;
const placesApiKey = process.env.PLACES_API_KEY;
const mapsApiKey = process.env.MAPS_API_KEY;
// Verify environment variables loaded (only during development)
console.log('recaptchaSite:', recaptchaSite, '\n');
console.log('recaptchaSecret:', recaptchaSecret, '\n');
const app = express();
app.use(express.json());
// Firebase Admin SDK setup with Application Default Credentials (ADC)
const { GoogleAuth } = require('google-auth-library');
admin.initializeApp({
// credential: admin.credential.applicationDefault(), // optional: explicit ADC
});
// Main API Endpoint
app.post('/api/data', async (req, res) => {
const appCheckToken = req.headers['x-firebase-appcheck'];
console.log("\n", "Token", "\n", "\n", appCheckToken, "\n")
try {
// Verify Firebase App Check token for security
const appCheckResult = await admin.appCheck().verifyToken(appCheckToken);
if (appCheckResult.appId) {
console.log('App Check verification successful!');
placesQuery(req, res);
} else {
console.error('App Check verification failed.');
res.status(403).json({ error: 'App Check verification failed.' });
}
} catch (error) {
console.error('Error verifying App Check token:', error);
res.status(500).json({ error: 'Error verifying App Check token.' });
}
});
// Function to query Google Places API
async function placesQuery(req, res) {
console.log('#################################');
console.log('\n', 'placesApiKey:', placesApiKey, '\n');
const queryObject = req.body.request;
console.log('\n','Request','\n','\n', queryObject, '\n')
const headers = {
'Content-Type': 'application/json',
'X-Goog-FieldMask': '*',
'X-Goog-Api-Key': placesApiKey,
'Referer': 'http://localhost:3000', // Update for production(ie.: req.hostname)
};
const myUrl = 'https://places.googleapis.com/v1/places:searchNearby';
try {
// Authenticate with ADC
const auth = new GoogleAuth();
const { credential } = await auth.getApplicationDefault();
const response = await axios.post(myUrl, queryObject, { headers, auth: credential });
console.log('############### SUCCESS','\n','\n','Response','\n','\n', );
const myBody = response.data;
myBody.places.forEach(place => {
console.log(place.displayName);
});
res.json(myBody); // Use res.json for JSON data
} catch (error) {
console.log('############### ERROR');
// console.error(error); // Log the detailed error for debugging
res.status(error.response.status).json(error.response.data); // Use res.json for errors too
}
}
// Configuration endpoint (send safe config data to the client)
app.get('/api/config', (req, res) => {
res.json({
mapsApiKey: process.env.MAPS_API_KEY,
recaptchaKey: process.env.RECAPTCHA_SITE_KEY,
});
});
// Serve static files
app.use(express.static('static'));
// Start the server
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server listening on port ${port}`, '\n');
});
7. Uygulamayı çalıştırın
Seçtiğiniz ortamda, sunucuyu terminalden çalıştırın ve http://localhost:3000 adresine gidin.
npm start
Bir jeton, genel değişken olarak oluşturulur, kullanıcının tarayıcı penceresinden gizlenir ve işlenmek üzere sunucuya iletilir. Jetonun ayrıntılarını sunucu günlüklerinde bulabilirsiniz. | Sunucunun işlevleri ve Places API Yakında Arama isteğine verdiği yanıtla ilgili ayrıntıları sunucu günlüklerinde bulabilirsiniz. |
Sorun giderme:
Kurulumda Google proje kimliğinin tutarlı olduğundan emin olun:
- .env dosyasında (GOOGLE_CLOUD_PROJECT değişkeni)
- terminal gcloud yapılandırmasında:
gcloud config set project your-project-id
- reCaptcha kurulumunda

- Firebase kurulumunda

Diğer
- Test ve sorun giderme amacıyla
script.jsiçinde reCAPTCHA site anahtarı yerine kullanılabilecek bir hata ayıklama jetonu oluşturun.

try {
// Initialize Firebase first
await firebase.initializeApp(firebaseConfig);
// Set the debug token
if (window.location.hostname === 'localhost') { // Only in development
await firebase.appCheck().activate(
'YOUR_DEBUG_FIREBASE_TOKEN', // Replace with the token from the console
true // Set to true to indicate it's a debug token
);
} else {
// Activate App Check
await firebase.appCheck().activate(recaptchaKey);
}
- Çok fazla başarısız kimlik doğrulama denemesi (ör. yanlış reCAPTCHA site anahtarı kullanma) geçici bir sınırlamaya neden olabilir.
FirebaseError: AppCheck: Requests throttled due to 403 error. Attempts allowed again after 01d:00m:00s (appCheck/throttled).
ADC Kimlik Bilgileri
- Doğru gcloud hesabında olduğunuzdan emin olun.
gcloud auth login
- Gerekli kitaplıkların yüklendiğinden emin olun.
npm install @googlemaps/places firebase-admin
- server.js dosyasında Firebase kitaplığının yüklendiğinden emin olun.
const {GoogleAuth} = require('google-auth-library');
- Yerel geliştirme: ADC'yi ayarlayın
gcloud auth application-default login
- Kimliğe bürünme: ADC kimlik bilgileri kaydedildi
gcloud auth application-default login --impersonate-service-account your_project@appspot.gserviceaccount.com
- Son olarak, aşağıdaki komut dosyasını test.js olarak kaydedip Terminal'de çalıştırarak ADC'yi yerel olarak test edin:
node test.js
const {GoogleAuth} = require('google-auth-library');
async function requestTestADC() {
try {
// Authenticate using Application Default Credentials (ADC)
const auth = new GoogleAuth();
const {credential} = await auth.getApplicationDefault();
// Check if the credential is successfully obtained
if (credential) {
console.log('Application Default Credentials (ADC) loaded successfully!');
console.log('Credential:', credential); // Log the credential object
} else {
console.error('Error: Could not load Application Default Credentials (ADC).');
}
// ... rest of your code ...
} catch (error) {
console.error('Error:', error);
}
}
requestTestADC();
8. İşlem tamamlandı. Tebrikler.
Takip adımları
App Engine'e dağıtım:
- Gerekli yapılandırma değişikliklerini yaparak projenizi Google App Engine'e dağıtıma hazırlayın.
- Uygulamanızı dağıtmak için
gcloudkomut satırı aracını veya App Engine konsolunu kullanın.
Firebase Authentication'ı geliştirme:
- Varsayılan ve Özel Jetonlar: Firebase hizmetlerinin daha kapsamlı kullanımı için Firebase özel jetonlarını uygulayın.
- Jeton Geçerlilik Süresi: Uygun jeton geçerlilik süreleri ayarlayın. Hassas işlemler için daha kısa (özel Firebase jetonu: en fazla bir saat), genel oturumlar için daha uzun (reCAPTCHA jetonu: 30 dakika ila 7 saat).
- reCAPTCHA'ya Alternatifleri Keşfedin: DeviceCheck (iOS), SafetyNet (Android) veya App Attest'in güvenlik ihtiyaçlarınıza uygun olup olmadığını araştırın.
Firebase ürünlerini entegre edin:
- Realtime Database veya Firestore: Uygulamanızın gerçek zamanlı veri senkronizasyonu ya da çevrimdışı özelliklere ihtiyacı varsa Realtime Database veya Firestore ile entegrasyon yapın.
- Cloud Storage: Cloud Storage'ı, resim veya video gibi kullanıcı tarafından oluşturulan içerikleri depolamak ve sunmak için kullanın.
- Kimlik doğrulama: Kullanıcı hesapları oluşturmak, giriş oturumlarını yönetmek ve şifre sıfırlama işlemlerini gerçekleştirmek için Firebase Authentication'dan yararlanın.
Mobil cihazlara genişletme:
- Android ve iOS: Mobil uygulamanız olacaksa hem Android hem de iOS platformları için sürümler oluşturun.
- Firebase SDK'ları: Firebase özelliklerini mobil uygulamalarınıza sorunsuz bir şekilde entegre etmek için Android ve iOS için Firebase SDK'larını kullanın.

