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 analize ihtiyacınız vardırCloud Firestore Security Rules. Cloud Firestore emülatörüyle, uygulamanızın genel özelliklerini ve davranışını prototip haline getirmenin ve test etmenin yanı sıra Cloud Firestore Security Rules'ınızın davranışını kontrol eden birim testleri de yazabilirsiniz.

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

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

Cloud Firestore Security Rules hakkında bilgi edinme

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

Cloud Firestore Security Rules iki parçadan oluşur:

  1. Veritabanınıza ait dokümanları tanımlayan bir match ifadesi.
  2. Bu dokümanlara erişimi kontrol eden bir allow ifadesi.

Firebase Authentication, kullanıcıların kimlik bilgilerini doğrular ve kullanıcıya dayalı ve role dayalı erişim sistemlerinin temelini oluşturur.

Cloud Firestore mobil/web istemci kitaplığından gelen her veritabanı isteği, herhangi bir veri okumadan veya yazmadan önce güvenlik kurallarınıza göre değerlendirilir. Kurallar, belirtilen doküman yollarından herhangi birine erişimi reddederse istek tamamıyla başarısız olur.

Cloud Firestore Security Rules'ü kullanmaya başlama başlıklı makalede Cloud Firestore Security Rules hakkında daha fazla bilgi edinin.

Emülatörü yükleme

Cloud Firestore emülatörünü yüklemek için Firebase CLI'yi 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 projesini başlatarak başlayın. Bu, Firebase CLI'yi 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, 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 ardından testler çalıştıktan sonra emülatörü kapatmak istersiniz. Bunu emulators:exec komutunu kullanarak kolayca yapabilirsiniz:

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

Emülatör, başlatıldığında varsayılan 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ı 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 kabul eder.
  • Çoğu Firebase SDK'sı doğrudan emülatörlerle çalışırken yalnızca @firebase/rules-unit-testing kitaplığı, Security Rules'da auth taklit etmeyi destekler. Bu da birim testlerini çok daha kolay hale getirir. Ayrıca kitaplık, aşağıda listelenen tüm verileri temizleme gibi emülatöre özgü birkaç özelliği destekler.
  • Emülatörler, istemci SDK'ları aracılığıyla sağlanan üretim Firebase Authentication 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 9 numaralı JavaScript SDK'sı hem de 8 numaralı SDK'sıyla birlikte bir Güvenlik Kuralları birim testi kitaplığı dağıtır. Kitaplık API'leri önemli ölçüde farklıdır. Daha basit ve emülatörlere bağlanmak için daha az kurulum gerektiren v9 test kitaplığını öneririz. Böylece, ü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ıma sunmaya devam ediyoruz.

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

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

v9 Kurallar Birim Testi kitaplığı, her zaman emülatörlerden haberdardır 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ılan birim testlerini uygulamak için:

  • initializeTestEnvironment'a çağrı göndererek RulesTestEnvironment oluşturma ve yapılandırma.
  • Kuralları tetiklemeden test verileri oluşturma. Bu işlemi, kuralları geçici olarak atlamanıza olanak tanıyan bir kolay yöntem kullanarak yapabilirsiniz.RulesTestEnvironment.withSecurityRulesDisabled
  • Test verileriyle ortamı temizlemek için RulesTestEnvironment.cleanup() veya RulesTestEnvironment.clearFirestore() gibi çağrılar içeren test grubu ve test başına önce/sonra kancaları ayarlama.
  • RulesTestEnvironment.authenticatedContext ve RulesTestEnvironment.unauthenticatedContext kullanarak kimlik doğrulama durumlarını taklit eden test durumları uygulama

Yaygın yöntemler ve yardımcı işlevler

v9 SDK'sındaki emülatöre özgü test yöntemlerine de bakın.

initializeTestEnvironment() => RulesTestEnvironment

Bu işlev, kural birim testi için bir test ortamı oluşturur. 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, bir TestEnvironmentConfig tanımlayan isteğe bağlı bir nesneyi kabul eder. Bu nesne, proje kimliği ve emülatör yapılandırma ayarlarından oluşabilir.

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 kullanıcı gibi davranan bir RulesTestContext oluşturur. Döndürülen bağlam üzerinden oluşturulan isteklere sahte bir kimlik doğrulama jetonu eklenir. İsteğe bağlı olarak, kimlik doğrulama jetonu yükü için özel hak taleplerini veya geçersiz kılma işlemlerini tanımlayan bir nesne iletin.

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(), '/users/alice'), { ... });

RulesTestEnvironment.unauthenticatedContext() => RulesTestContext

Bu yöntem, kimlik doğrulama üzerinden giriş yapmayan 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 kurulumu işlevi çalıştırın.

Bu yöntem, Güvenlik Kurallarını Atlama bağlamını alan ve bir promise döndüren bir geri çağırma işlevi alır. Sözleşme çözüldükten veya reddedildikten sonra 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 uygulama emülatörüne özel veri temizleme yöntemini kullanın.

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

Bu, test amaçlı bir yardımcı program işlevidir.

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

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

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

Bu, test amaçlı bir yardımcı program işlevidir.

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

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

Emülatöre özel yöntemler

v9 SDK'sındaki yaygın test yöntemleri ve yardımcı program işlevleri konusuna da bakın.

RulesTestEnvironment.clearFirestore() => Promise<void>

Bu yöntem, Firestore emülatörü için yapılandırılmış projectId'ye 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 API'leriyle (modüler v9 veya uyumlu v9) kullanılabilir.

Kural değerlendirmelerini görselleştirme

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

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

Güvenlik Kuralı değerlendirmelerini gösteren Firestore Emulator İstekler İzleyicisi

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 emülatörde açık bir uç noktayı sorgulayın. Tarayıcı dostu bir sürüm için aşağıdaki URL'yi kullanın:

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

Bu işlem, kurallarınızı ifade ve alt ifadelere ayırır. Fareyle üzerine geldiğinizde değerlendirmelerin sayısı ve döndürülen değerler gibi daha fazla bilgi edinebilirsiniz. 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. Cloud Firestore projesini açıkça 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 herkese açık kullanıcı adı, sağladığınız öğe olarak başarıyla kimlik doğrulamış gibi davranır. null parametresini gönderirseniz kimliği doğrulanmamış bir kullanıcı gibi davranır (örneğin, auth != null kuralları geçersiz 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 anormal 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ışı tutarlı değil

Testlerinizde herhangi bir değişiklik yapılmamasına rağmen zaman zaman başarılı ve başarısız sonuçlar alıyorsanız testlerin doğru şekilde sıralandığını doğrulamanız gerekebilir. Emülatörle yapılan etkileşimlerin çoğu eşzamansız olduğundan, tüm eşzamansız kodun doğru şekilde sıralandığından emin olun. Sözleşmeleri zincirleyerek veya await gösterimini bolca kullanarak sıralamayı düzeltebilirsiniz.

Özellikle aşağıdaki asenkron işlemleri inceleyin:

  • Örneğin initializeTestEnvironment ile güvenlik kuralları ayarlama.
  • Ö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 geçer.

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

  • Her test için benzersiz proje kimlikleri kullanın. Bunu yapmayı seçerseniz her testin bir parçası olarak initializeTestEnvironment işlevini çağırmanız gerektiğini unutmayın. 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 (örneğin, her test için farklı bir koleksiyon kullanın).
  • Bir test sırasında yazılan tüm verileri silin.

Test kurulumu çok karmaşık

Testinizi oluştururken verileri Cloud Firestore Security Rules'ün aslında izin vermediği bir şekilde değiştirmek isteyebilirsiniz. Kurallarınız test kurulumunu karmaşık hale getiriyorsa okuma ve yazma işlemlerinin PERMISSION_DENIED hatalarını tetiklememesi için kurulum adımlarınızda RulesTestEnvironment.withSecurityRulesDisabled kullanmayı deneyin.

Ardından, testiniz sırasıyla RulesTestEnvironment.authenticatedContext ve unauthenticatedContext kullanarak kimliği doğrulanmış veya doğrulanmamış bir kullanıcı olarak işlem gerçekleştirebilir. Bu sayede, Cloud Firestore Security Rules'ün farklı durumları doğru şekilde izin verdiğini / reddettiğini doğrulayabilirsiniz.