Satır düzeyi erişim ve kiracılar
CPalius'ta "bu kullanıcı bu kaydı görebilir mi?" sorusu sorgu çalışmadan önce SQL'e çevrilir. Liste ekranları satır satır yetki sormaz; WHERE koşulu zaten yalnızca görülebilir satırları getirir. Üç mekanizma birlikte çalışır.
1. .own / .any kapsamı: QueryScopeApplier
Yetenekler iki sonekle kurulur: node.post.edit.any (herkesin yazısı) ve node.post.edit.own (yalnızca kendi yazısı). QueryScopeApplier::apply() bir sorguya kapsam ekler:
| Kullanıcının sahip olduğu | Eklenen koşul |
|---|---|
.any |
Koşul eklenmez (tüm satırlar) |
yalnızca .own |
sahip alanı = ben |
| ikisi de yok | 1 = 0 (boş sonuç) |
Kural şudur: yetkisiz kullanıcı hiçbir zaman süzülmemiş tablo görmez. Hiçbir koşulun uygulanmadığı bir sonuç yoktur; yetki yoksa sonuç boştur.
$qb = $repository->createQueryBuilder('p');
$this->scope->apply($qb, 'p', 'node.post.edit', ownerField: 'author');
Üçüncü parametre yetenek kökü (soneksiz), ownerField sahip sütunudur.
2. Tek kayıt için izin: EntityAccessManager
Bazen "bu kullanıcı yalnızca şu kaydı düzenleyebilsin" gerekir. EntityAccessManager kayıt bazlı izin kayıtları (grant) tutar; yetenek ad alanı aynıdır, paralel bir sistem yoktur:
$access->grantToUser('node', $id, 'node.post.edit', $userId);
$access->grantToRole('node', $id, 'node.post.edit', 'editor');
$access->grantToAnyone('node', $id, 'node.post.view');
$access->revokeFromUser('node', $id, 'node.post.edit', $userId);
İki özelliği önemlidir:
- Yeniden oluşturma adımı yoktur. Her izin satırı yazıldığı anda tek başına doğrudur; bir modül, görünürlük değiştiği an izni yazar.
- Sorguya katlanır.
buildScopeCondition()izinleri, çağıranın sorgusuna ilişkiliEXISTSalt sorgusu olarak ekler.QueryScopeApplierkayıt izinlerini de bu yolla hesaba katar:.ownyetkisi olmayan ama bu kayda izni olan kullanıcı kaydı yine görür.
Çekirdek, tek bir kaydı başkasıyla paylaşma arayüzü sunmaz; yalnızca mekanizmayı verir. Notlar modülü bunun örneğidir: kendi küçük paylaşım tablosu ve NoteAccess hizmeti ile aynı fikri uygular.
3. Çok kiracılı veri: TenantFilter
#[CpResource(multiTenant: true)] taşıyan bir varlığın her sorgusuna otomatik olarak tenant_id = :tenant_id eklenir. Bu bir Doctrine SQLFilter'dır:
- Yalnızca
multiTenant: trueişaretli varlıklara uygulanır; diğerlerine dokunmaz. - Parametre verilmemişse hiçbir koşul eklemez. Filtre, etkinleştirilip kiracı kimliği tanımlanana kadar kapalıdır; bu yüzden tek kiracılı sitede maliyeti yoktur.
- Kiracı koşulu, kodunuzdaki her sorguda tekrar yazılmaz; unutulması mümkün değildir.
Ne zaman hangisi
| İhtiyaç | Araç |
|---|---|
| "Kendi içeriğimi/herkesinkini" listelemek | QueryScopeApplier (.own/.any) |
| Bir kaydı belirli kişiye ya da role açmak | EntityAccessManager |
| Müşteri başına yalıtılmış veri | multiTenant: true + TenantFilter |
| Modüle özgü paylaşım (not, belge) | Kendi tablonuz + sorguya çevrilen erişim sınıfı (Notlar örneği) |
Güvenlik notları
- Erişimi her eylemde denetleyin: kimliğini tahmin eden kullanıcı için kayıt bulunmamış gibi 404 döndürün (403 varlığı ele verir).
- Listede kapsamı SQL'e çevirmek, şablonda
is_grantedile süzmekten hem daha güvenli hem daha hızlıdır; süzülmüş satırlar sayfalamayı da bozmaz. - Menüden gizlemek erişimi kapatmaz; bkz. Menü ve yetkiler.