İçeriğe geç

Yetki sistemi

CPalius'ta "yönetici mi?" diye sorulmaz. Sorulan şey şudur: bu kullanıcı bu eylemi yapabilir mi? Eylemler dize olarak adlandırılır (node.post.edit.own, media.upload, system.update.manage) ve bu dizelere yetenek (capability) denir. Uygulama kodunda ROLE_ADMIN kontrolü yoktur.

Yetenek adları

Ad, alan.nesne.eylem[.kapsam] biçimindedir:

system.update.manage        sistemi güncelle
node.post.view.own          yalnız kendi yazılarını gör
node.post.edit.any          herkesin yazısını düzenle
media.upload                medya yükle
forum.post.report           forum iletisini şikâyet et
text_format.full_html.use   "tam HTML" metin biçimini kullan

Kapsam: .own ve .any

Sahibi olan kayıtlarda iki kapsam vardır:

  • .own: yalnızca kendi kaydın üzerinde geçerli
  • .any: herhangi bir kayıt üzerinde geçerli

Kapsamsız bir yetenek (ör. node.post.publish) kayıttan bağımsız geçerlidir.

Yetenekler nereden gelir?

Bir yetenek kayıt defterinde (CapabilityRegistry) yoksa geçersizdir ve reddedilir. Böylece yazım hatası ("node.post.edt") sessizce yetki vermez, sessizce reddeder.

Kaynaklar:

  1. Çekirdek: cp-core/config/capabilities.yaml. system.* (modül, güncelleme, güvenlik, yedek, cron, kuyruk, API, webhook, alanlar, kullanıcılar, yerelleştirme…), taxonomy.manage, content.*, account.*, core.*, text_format.*.use, admin.*.
  2. Modüller: her modülün Resources/config/capabilities.yaml dosyası.
  3. Kaynaklar: #[CpResource(capabilities: ['create', 'edit', ...])] kısaltmaları vehicle.create gibi tam adlara açılır; kodda elle yazmanız gerekmez.
  4. Sözlükler: taksonomi sözlükleri kendi yeteneklerini otomatik kaydeder.

cp:debug komutu, kayıt defterinin bulduğu tüm yetenekleri listeler.

Roller

Roller veritabanında değil, cp-content/config/sync/user.role.<id>.yaml dosyalarındadır. Sebep: roller de kod gibi sürümlenmeli, gözden geçirilmeli ve ortamlar arasında Git ile taşınmalıdır.

role:
    id: editor
    label: 'role.label.editor'
    capabilities:
        - admin.dashboard.view
        - node.post.view.own
        - node.post.create
        - node.post.edit.own
        - media.upload
        - text_format.basic_html.use

Çekirdekle gelen roller:

Rol Yetenekler
admin '*' (joker): kayıt defterindeki tüm yetenekler. Kaldırılan ya da tanımsız bir yetenek otomatik düşer
editor Studio panosu, kendi yazı ve sayfaları (oluştur, düzenle, sil, yayınla), yorum moderasyonu, medya, forum etkileşimi, metin biçimleri
member Kayıtlı üye: forum etkileşimi, profil, avatar, kısıtlı metin biçimi. İçerik yönetimi vermez, kayıt olmak içerik yetkisi kazandırmamalıdır

Bozuk bir rol dosyası (geçersiz YAML, eksik id, eksik capabilities) o rolü atlar; asla fazladan yetki vermez. Ayrıştırılan harita önbelleğe alınır ve dosya değişim zamanıyla geçersiz kılınır.

Kapsamsız yetenek verirken dikkat

forum.post.edit gibi kapsamsız bir yetenek, oylayıcı tarafından genel (her kayda) sayılır. Bu yüzden member rolüne yalnızca forum.post.edit.own verilmiştir. Modülünüzde kapsamlı varyantlar tanımlıyorsanız rollere hep kapsamlı olanı verin.

Karar akışı

Her yetki sorusu tek bir kapıdan geçer: is_granted('capability', $konu). Oylayıcı (CPaliusVoter) şu sırayla karar verir:

  1. Kayıt defteri: yetenek tanımsızsa çekimser (hiçbir zaman izin değil).
  2. Kullanıcı istisnası: reddet. Kullanıcıya özel deny her şeyden önce gelir ve kazanır.
  3. Rol yetenekleri: kullanıcının rollerinden biri yeteneği içeriyor mu?
  4. Kullanıcı istisnası: ver. Kullanıcıya özel grant.
  5. .own denetimi: kayıt OwnableInterface ile sahibini söylüyorsa, sahibi bu kullanıcı mı?
  6. Kayıt bazlı izin: bu tek kayıt için kullanıcıya, role ya da herkese verilmiş bir izin var mı?
  7. Erişim olayı: modüller bir hook ile kararı etkileyebilir (sınırlı).

Kullanıcıya özel istisna

Bir kullanıcıya rolünden bağımsız olarak tek bir yetenek verilebilir ya da alınabilir (UserCapabilityOverride, grant / deny). Ayrıcalık yükselmesini önlemek için bu istisnalar bir politika katmanından geçer.

Kayıt bazlı izin (row-level)

"Bu kullanıcı / bu rol / herkes, şu tek kayıt üzerinde şu yeteneği kullanabilir." (EntityAccessManager). Örneğin bir grup üyeliği ya da paylaşılan bir davetiye bir kaydın görünürlüğünü değiştirdiğinde modül izni o anda yazar. Toplu bir "yeniden kur" adımı yoktur: her izin satırı yazıldığı anda doğrudur.

$access->grantToUser('album', $album->getId(), 'album.view', $userId, $grantedBy);
$access->grantToRole('album', $album->getId(), 'album.view', 'member');
$access->grantToAnyone('album', $album->getId(), 'album.view');
$access->revokeAllForEntity('album', $album->getId());

Listelerde: yetki SQL'e çevrilir

100 satırlık bir listede her satır için oylayıcı çalıştırmak, ciddi bir N+1 sorunu yaratır. CPalius bunu QueryScopeApplier ile çözer: kullanıcının yetenekleri (.any, .own, kayıt izinleri) doğrudan sorgunun WHERE koşuluna eklenir.

$qb = $repo->createQueryBuilder('p');
$scope->apply($qb, 'p', 'node.post.view', 'author');
// .any varsa filtre yok; yalnız .own varsa  AND p.author = :me
// kayıt izni varsa  OR EXISTS(...)
// hiçbiri yoksa     1 = 0  (boş sonuç)

Kural: yetki yoksa sonuç boş gelir, asla filtresiz tablo gelmez.

Metin biçimi yetenekleri

Zengin metin alanı hangi süzgeçlerden geçeceğini bir metin biçimi ile söyler. Kullanıcının hangi biçimleri seçebileceği yetenekle belirlenir: text_format.restricted.use, text_format.basic_html.use, text_format.full_html.use, text_format.markdown.use. Üye yalnızca kısıtlı biçimi kullanır; editör tam HTML'e kadar çıkar.

Çok kiracılı (SaaS) kullanım

#[CpResource(multiTenant: true)] işaretli kaynaklarda bir Doctrine SQL filtresi tüm SELECT'lere AND tenant_id = :aktif_kiracı ekler, yazmalarda kiracı otomatik damgalanır. Geliştirici disiplinine güvenilmez, yalıtım varsayılandır.

Modül yazarı için

# Resources/config/capabilities.yaml
capabilities:
    - mymodule.item.view.own
    - mymodule.item.view.any
    - mymodule.item.create
    - mymodule.item.edit.own
    - mymodule.item.edit.any
    - mymodule.settings.manage
#[Route('/admin/items/{id}/edit', name: 'admin_item_edit')]
#[IsGranted('mymodule.item.edit')]          // kapsamsız yazılırsa .own/.any'den biri yeterli sayılır
public function edit(Item $item): Response { /* ... */ }
  • Menüde: #[CpAdminMenu(capability: 'mymodule.item.view.own|mymodule.item.view.any')]: | ile "veya".
  • Yeni yetenekleri rollere eklemek için modül kurulumcusu user.role.*.yaml dosyalarına yazabilir (Portal ve Vitrin bunu yapar).
  • cp:doctor rollerde tanımsız bir yetenek kalmışsa uyarır.
Son güncelleme: 13.10.2026