Cloud Firestore Güvenlik Kurallarınızı test etme

Uygulamanızı oluştururken Cloud Firestore veritabanınıza erişimi kilitlemek isteyebilirsiniz. Ancak lansmandan önce daha ayrıntılı bir Cloud Firestore Security Rules. Cloud Firestore emülatörüyle uygulamanızın genel özelliklerinin ve davranışının prototipini oluşturup test etmenin yanı sıra Cloud Firestore Security Rules davranışını kontrol eden birim testleri yazabilirsiniz.

Hızlı başlangıç kılavuzu

Basit kurallara sahip birkaç temel test durumu için hızlı başlangıç örneğini deneyin.

Cloud Firestore Security Rules hakkında bilgi edinin

Mobil ve web istemci kitaplıklarını kullanırken sunucusuz kimlik doğrulama, yetkilendirme ve veri doğrulama için Firebase Authentication ve Cloud Firestore Security Rules'ı uygulayın.

Cloud Firestore Security Rules iki bölümden oluşur:

  1. Veritabanınızdaki belgeleri tanımlayan bir match ifadesi.
  2. Bu belgelere erişimi kontrol eden bir allow ifadesi.

Firebase Authentication, kullanıcıların kimlik bilgilerini doğrular ve kullanıcı tabanlı ile rol tabanlı erişim sistemlerinin temelini oluşturur.

Kurallar mobil/web istemci kitaplığından gelen her veritabanı isteği, herhangi bir veri okunmadan veya yazılmadan önce güvenlik kurallarınıza göre değerlendirilir. Kurallar, belirtilen belge yollarından herhangi birine erişimi reddederse isteğin tamamı başarısız olur.

Cloud Firestore Security Rules hakkında daha fazla bilgi için Cloud Firestore Security Rules hizmetini kullanmaya başlama başlıklı makaleyi inceleyin.

Emülatörü yükleme

Cloud Firestore emülatörünü yüklemek için Firebase CLI'yı kullanın ve aşağıdaki komutu çalıştırın:

firebase setup:emulators:firestore

Emülatörü çalıştırma

Çalışma dizininizde bir Firebase projesi başlatarak işe koyulun. Bu, Firebase CLI'yı kullanırken uygulanan yaygın bir ilk adımdır.

firebase init

Aşağıdaki komutu kullanarak emülatörü başlatın. Emülatör, siz işlemi sonlandırana kadar çalışır:

firebase emulators:start --only firestore

Çoğu durumda emülatörü başlatmak, bir test paketi çalıştırmak ve testler çalıştırıldıktan sonra emülatörü kapatmak istersiniz. Bunu emulators:exec komutunu kullanarak kolayca yapabilirsiniz:

firebase emulators:exec --only firestore "./my-test-script.sh"

Başlatıldığında emülatör, varsayılan bir bağlantı noktasında (8080) çalışmaya çalışır. firebase.json dosyanızın "emulators" bölümünü değiştirerek emülatör bağlantı noktasını değiştirebilirsiniz:

{
  // ...
  "emulators": {
    "firestore": {
      "port": "YOUR_PORT"
    }
  }
}

Emülatörü çalıştırmadan önce

Emülatörü kullanmaya başlamadan önce aşağıdakileri göz önünde bulundurun:

  • Emülatör başlangıçta firebase.json dosyanızın firestore.rules alanında belirtilen kuralları yükler. Cloud Firestore Security Rules dosyanızı içeren yerel bir dosyanın adını bekler ve bu kuralları tüm projelere uygular. Yerel dosya yolunu sağlamazsanız veya aşağıda açıklandığı gibi loadFirestoreRules yöntemini kullanmazsanız emülatör, tüm projeleri açık kurallara sahip olarak değerlendirir.
  • Çoğu Firebase SDK'sı emülatörlerle doğrudan çalışırken yalnızca @firebase/rules-unit-testing kitaplığı, güvenlik kurallarında auth taklit etmeyi destekleyerek birim testlerini çok daha kolay hale getirir. Ayrıca kitaplık, aşağıda listelendiği gibi tüm verileri temizleme gibi emülatöre özgü birkaç özelliği de destekler.
  • Emülatörler, istemci SDK'ları aracılığıyla sağlanan üretim Firebase Auth jetonlarını da kabul eder ve kuralları buna göre değerlendirir. Bu sayede, entegrasyon ve manuel testlerde uygulamanızı doğrudan emülatörlere bağlayabilirsiniz.

Yerel birim testleri çalıştırma

v9 JavaScript SDK'sı ile yerel birim testleri çalıştırma

Firebase, hem sürüm 9 JavaScript SDK'sı hem de sürüm 8 SDK'sı ile bir Güvenlik Kuralları birim testi kitaplığı dağıtır. Kitaplık API'leri önemli ölçüde farklıdır. Emülatörlere bağlanmak için daha az kurulum gerektiren ve daha akıcı olan v9 test kitaplığını kullanmanızı öneririz. Bu sayede üretim kaynaklarının yanlışlıkla kullanılmasını güvenli bir şekilde önleyebilirsiniz. Geriye dönük uyumluluk için v8 test kitaplığını kullanılabilir tutmaya devam ediyoruz.

Yerel olarak çalışan emülatörle etkileşim kurmak için @firebase/rules-unit-testing modülünü kullanın. Zaman aşımı veya ECONNREFUSED hataları alırsanız emülatörün gerçekten çalıştığını tekrar kontrol edin.

async/await gösterimini kullanabilmeniz için Node.js'nin yeni bir sürümünü kullanmanızı önemle tavsiye ederiz. Test etmek isteyebileceğiniz davranışların neredeyse tamamı eşzamansız işlevler içerir ve test modülü, Promise tabanlı kodla çalışacak şekilde tasarlanmıştır.

v9 Kuralları Birim Testi kitaplığı, emülatörleri her zaman algılar ve üretim kaynaklarınıza hiçbir zaman dokunmaz.

Kitaplığı v9 modüler içe aktarma ifadelerini kullanarak içe aktarırsınız. Örneğin:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment
} from "@firebase/rules-unit-testing"

// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.

İçe aktarıldıktan sonra birim testlerini uygulamak için şunları yapmanız gerekir:

  • initializeTestEnvironment çağrısıyla RulesTestEnvironment oluşturma ve yapılandırma.
  • Kuralları tetiklemeden test verilerini ayarlamak için kuralları geçici olarak atlamanıza olanak tanıyan kullanışlı bir yöntem kullanabilirsiniz. RulesTestEnvironment.withSecurityRulesDisabled
  • Test verilerini ve ortamını temizlemek için RulesTestEnvironment.cleanup() veya RulesTestEnvironment.clearFirestore() gibi çağrılarla test paketini ve test öncesi/sonrası kancalarını ayarlama.
  • RulesTestEnvironment.authenticatedContext ve RulesTestEnvironment.unauthenticatedContext kullanarak kimlik doğrulama durumlarını taklit eden test durumları uygulama

Yaygın yöntemler ve hizmet işlevleri

Ayrıca v9 SDK'daki emülatöre özgü test yöntemlerine de bakın.

initializeTestEnvironment() => RulesTestEnvironment

Bu işlev, kuralların birim testi için bir test ortamı başlatır. Test kurulumu için önce bu işlevi çağırın. Başarılı bir yürütme için emülatörlerin çalışıyor olması gerekir.

İşlev, proje kimliği ve emülatör yapılandırma ayarlarından oluşabilen bir TestEnvironmentConfig tanımlayan isteğe bağlı bir nesneyi kabul eder.

let testEnv = await initializeTestEnvironment({
  projectId: "demo-project-1234",
  firestore: {
    rules: fs.readFileSync("firestore.rules", "utf8"),
  },
});

RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext

Bu yöntem, kimliği doğrulanmış bir Authentication kullanıcısı gibi davranan bir RulesTestContext oluşturur. Döndürülen bağlam aracılığıyla oluşturulan isteklerde sahte bir kimlik doğrulama jetonu ekli olur. İsteğe bağlı olarak, kimlik doğrulama jetonu yükleri için özel hak taleplerini veya geçersiz kılmaları tanımlayan bir nesne iletebilirsiniz.

initializeTestEnvironment ile yapılandırılanlar da dahil olmak üzere yapılandırılmış tüm emülatör örneklerine erişmek için testlerinizde döndürülen test bağlamı nesnesini kullanın.

// Assuming a Firestore app and the Firestore emulator for this example
import { setDoc } from "firebase/firestore";

const alice = testEnv.authenticatedContext("alice", { … });
// Use the Firestore instance associated with this context
await assertSucceeds(setDoc(alice.firestore().doc('/users/alice'), { ... });

RulesTestEnvironment.unauthenticatedContext() => RulesTestContext

Bu yöntem, Kimlik Doğrulama aracılığıyla giriş yapmamış bir istemci gibi davranan bir RulesTestContext oluşturur. Döndürülen bağlam aracılığıyla oluşturulan isteklerde Firebase Auth jetonları eklenmez.

initializeTestEnvironment ile yapılandırılanlar da dahil olmak üzere yapılandırılmış tüm emülatör örneklerine erişmek için testlerinizde döndürülen test bağlamı nesnesini kullanın.

// Assuming a Cloud Storage app and the Storage emulator for this example
import { getStorage, ref, deleteObject } from "firebase/storage";

const alice = testEnv.unauthenticatedContext();

// Use the Cloud Storage instance associated with this context
const desertRef = ref(alice.storage(), 'images/desert.jpg');
await assertSucceeds(deleteObject(desertRef));

RulesTestEnvironment.withSecurityRulesDisabled()

Güvenlik Kuralları devre dışı bırakılmış gibi davranan bir bağlamla test kurulum işlevi çalıştırın.

Bu yöntem, Security-Rules'u atlayan bağlamı alan ve bir promise döndüren bir geri çağırma işlevi alır. Promise çözümlendiğinde / reddedildiğinde bağlam yok edilir.

RulesTestEnvironment.cleanup()

Bu yöntem, test ortamında oluşturulan tüm RulesTestContexts öğelerini yok eder ve temel kaynakları temizleyerek temiz bir çıkış sağlar.

Bu yöntem, emülatörlerin durumunu hiçbir şekilde değiştirmez. Testler arasında verileri sıfırlamak için uygulamaya özel emülatör veri temizleme yöntemini kullanın.

assertSucceeds(pr: Promise<any>)) => Promise<any>

Bu, bir test durumu hizmet işlevidir.

İşlev, bir emülatör işlemini sarmalayan sağlanan Promise'in Güvenlik Kuralları ihlali olmadan çözüleceğini onaylar.

await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

assertFails(pr: Promise<any>)) => Promise<any>

Bu, bir test durumu hizmet işlevidir.

İşlev, emülatör işlemini sarmalayan sağlanan Promise'in bir Güvenlik Kuralları ihlali nedeniyle reddedileceğini onaylar.

await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });

Emülatöre özel yöntemler

Ayrıca v9 SDK'daki yaygın test yöntemlerine ve yardımcı işlevlere de göz atın.

RulesTestEnvironment.clearFirestore() => Promise<void>

Bu yöntem, Firestore emülatörü için yapılandırılmış projectId kimliğine ait Firestore veritabanındaki verileri temizler.

RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;

Bu yöntem, bu test bağlamı için bir Firestore örneği alır. Döndürülen Firebase JS istemci SDK'sı örneği, istemci SDK'sı API'leriyle (v9 modüler veya v9 uyumlu) kullanılabilir.

Kural değerlendirmelerini görselleştirme

Cloud Firestore emülatörü, Firebase Güvenlik Kuralları için değerlendirme izleme de dahil olmak üzere istemci isteklerini Emulator Suite kullanıcı arayüzünde görselleştirmenize olanak tanır.

Her isteğin ayrıntılı değerlendirme sırasını görüntülemek için Firestore > İstekler sekmesini açın.

Güvenlik Kuralları değerlendirmelerini gösteren Firestore Emulator Requests Monitor

Test raporları oluşturma

Bir dizi test çalıştırdıktan sonra, güvenlik kurallarınızın her birinin nasıl değerlendirildiğini gösteren test kapsamı raporlarına erişebilirsiniz.

Raporları almak için emülatör çalışırken açık bir uç noktayı sorgulayın. Tarayıcıda açılabilen bir sürüm için aşağıdaki URL'yi kullanın:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html

Bu, kurallarınızı ifadelere ve alt ifadelere ayırır. Değerlendirme sayısı ve döndürülen değerler gibi daha fazla bilgi için fareyle bunların üzerine gelebilirsiniz. Bu verilerin ham JSON sürümü için sorgunuza aşağıdaki URL'yi ekleyin:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage

Emülatör ile üretim arasındaki farklar

  1. Açıkça bir Cloud Firestore projesi oluşturmanız gerekmez. Emülatör, erişilen tüm örnekleri otomatik olarak oluşturur.
  2. Cloud Firestore emülatörü normal Firebase Authentication akışıyla çalışmaz. Bunun yerine, Firebase Test SDK'sında rules-unit-testing kitaplığında auth alanı alan initializeTestApp() yöntemini sağladık. Bu yöntem kullanılarak oluşturulan Firebase tanıtıcısı, sağladığınız varlık olarak kimlik doğrulamasını başarıyla tamamlamış gibi davranır. null değerini iletirseniz kimliği doğrulanmamış bir kullanıcı gibi davranır (örneğin, auth != null kuralları başarısız olur).

Bilinen sorunları giderme

Cloud Firestore emülatörünü kullanırken aşağıdaki bilinen sorunlarla karşılaşabilirsiniz. Karşılaştığınız düzensiz davranışları gidermek için aşağıdaki talimatları uygulayın. Bu notlar, Güvenlik Kuralları birim testi kitaplığı göz önünde bulundurularak yazılmıştır ancak genel yaklaşımlar tüm Firebase SDK'ları için geçerlidir.

Test davranışı tutarsız

Testlerinizde herhangi bir değişiklik yapılmamasına rağmen testleriniz bazen başarılı bazen başarısız oluyorsa testlerin doğru şekilde sıralandığını doğrulamanız gerekebilir. Emülatörle yapılan etkileşimlerin çoğu eşzamansızdır. Bu nedenle, tüm eşzamansız kodların doğru şekilde sıralandığından emin olun. Sıralamayı, promise'leri zincirleyerek veya await notasyonunu bolca kullanarak düzeltebilirsiniz.

Özellikle aşağıdaki eş zamansız işlemleri inceleyin:

  • Örneğin initializeTestEnvironment ile güvenlik kuralları belirleme
  • Örneğin, db.collection("users").doc("alice").get() ile veri okuma ve yazma.
  • assertSucceeds ve assertFails dahil olmak üzere operasyonel iddialar.

Testler yalnızca emülatörü ilk kez yüklediğinizde başarılı olur

Emülatör durum bilgisi içerir. Yazılan tüm verileri bellekte depoladığı için emülatör kapandığında tüm veriler kaybolur. Aynı proje kimliği için birden fazla test çalıştırıyorsanız her test, sonraki testleri etkileyebilecek veriler üretebilir. Bu davranışı atlamak için aşağıdaki yöntemlerden herhangi birini kullanabilirsiniz:

  • Her test için benzersiz proje kimlikleri kullanın. Bunu yapmayı seçerseniz her test kapsamında initializeTestEnvironment yöntemini çağırmanız gerekir. Kurallar yalnızca varsayılan proje kimliği için otomatik olarak yüklenir.
  • Testlerinizi, daha önce yazılmış verilerle etkileşime girmeyecek şekilde yeniden yapılandırın (ör. her test için farklı bir koleksiyon kullanın).
  • Test sırasında yazılan tüm verileri silin.

Test kurulumu çok karmaşık

Testinizi ayarlarken verileri, Cloud Firestore Security Rules'nizin normalde izin vermeyeceği şekilde değiştirmek isteyebilirsiniz. Kurallarınız test kurulumunu karmaşıklaştırıyorsa kurulum adımlarınızda RulesTestEnvironment.withSecurityRulesDisabled kullanmayı deneyin. Böylece okuma ve yazma işlemleri PERMISSION_DENIED hatalarını tetiklemez.

Ardından testiniz, sırasıyla RulesTestEnvironment.authenticatedContext ve unauthenticatedContext kullanarak kimliği doğrulanmış veya doğrulanmamış bir kullanıcı olarak işlem yapabilir. Bu sayede Cloud Firestore Security Rules politikanızın farklı durumlara doğru şekilde izin verip vermediğini veya reddedip reddetmediğini doğrulayabilirsiniz.