ACL ve Denetleyiciler
Her şeyden önce: Bunlar çoğunlukla farklı şeyler / katmanlar. Örnek denetleyici kodunu eleştirirken, her ikisini de bir araya getiriyor - en açık şekilde çok sıkı.
tereško , bunu dekoratör modeliyle nasıl daha fazla ayrıştırabileceğinizi zaten özetledi .
Önce bir adım geriye gidip karşılaştığınız asıl sorunu arar ve sonra bunu biraz tartışırdım.
Bir yandan, kendilerine komut verilen işi yapan denetleyicilere sahip olmak istiyorsunuz (komut veya eylem, hadi ona komut diyelim).
Öte yandan, uygulamanıza ACL koyabilmek istiyorsunuz. Bu ACL'lerin çalışma alanı, sorunuzu doğru anladıysam, uygulamalarınızın belirli komutlarına erişimi kontrol etmek olmalıdır.
Bu nedenle bu tür bir erişim kontrolü, bu ikisini bir araya getiren başka bir şeye ihtiyaç duyar. Bir komutun içinde yürütüldüğü bağlama bağlı olarak, ACL devreye girer ve belirli bir komutun belirli bir konu (örneğin kullanıcı) tarafından yürütülüp yürütülmeyeceğine karar verilmesi gerekir.
Bu noktaya sahip olduğumuz şeyi özetleyelim:
ACL bileşeni burada merkezidir: En azından komut hakkında bir şeyler bilmesi (komutu kesin olarak tanımlamak için) ve kullanıcıyı tanımlayabilmesi gerekir. Kullanıcılar normalde benzersiz bir kimlikle kolayca tanımlanır. Ancak genellikle web uygulamalarında hiç tanımlanmayan, genellikle konuk, anonim, herkes vb. Olarak adlandırılan kullanıcılar vardır. Bu örnek için, ACL'nin bir kullanıcı nesnesini tüketebileceğini ve bu ayrıntıları saklayabileceğini varsayıyoruz. Kullanıcı nesnesi, uygulama istek nesnesine bağlıdır ve EKL bunu kullanabilir.
Bir komutu tanımlamaya ne dersiniz? MVC desenini yorumlamanız, bir komutun bir sınıf adı ve bir yöntem adından oluşan bir bileşik olduğunu gösterir. Daha yakından bakarsak, bir komut için argümanlar (parametreler) bile vardır. Yani bir komutu tam olarak neyin tanımladığını sormak geçerli mi? Sınıf adı, yöntem adı, bağımsız değişkenlerin sayısı veya adları, hatta herhangi bir bağımsız değişken içindeki veriler veya bunların bir karışımı mı?
ACL'lemenizdeki bir komutu tanımlamanız gereken ayrıntı düzeyine bağlı olarak, bu çok değişebilir. Örnek için basit tutalım ve bir komutun sınıf adı ve yöntem adı ile tanımlandığını belirtelim.
Dolayısıyla, bu üç parçanın (ACL, Komut ve Kullanıcı) birbirine nasıl ait olduğu bağlamı artık daha net.
Hayali bir ACL bileşeni ile aşağıdakileri yapabiliriz diyebiliriz:
$acl->commandAllowedForUser($command, $user);
Sadece burada neler olduğuna bakın: Hem komutu hem de kullanıcıyı tanımlanabilir hale getirerek, ACL işini yapabilir. ACL'nin işi, hem kullanıcı nesnesinin hem de somut komutun çalışmasıyla ilgisizdir.
Eksik olan tek bir parça var, bu havada yaşayamaz. Ve öyle değil. Bu nedenle, erişim kontrolünün devreye girmesi gereken yeri bulmanız gerekiyor. Standart bir web uygulamasında neler olduğuna bir göz atalım:
User -> Browser -> Request (HTTP)
-> Request (Command) -> Action (Command) -> Response (Command)
-> Response(HTTP) -> Browser -> User
Bu yeri bulmak için, somut komutun yerine getirilmesinden önce olması gerektiğini biliyoruz, bu yüzden bu listeyi azaltabiliriz ve yalnızca aşağıdaki (potansiyel) yerlere bakmamız gerekir:
User -> Browser -> Request (HTTP)
-> Request (Command)
Uygulamanızın bir noktasında, belirli bir kullanıcının somut bir komut gerçekleştirmeyi talep ettiğini biliyorsunuz. Burada zaten bir çeşit ACL işlemi yapıyorsunuz: Bir kullanıcı mevcut olmayan bir komut isterse, bu komutun yürütülmesine izin vermezsiniz. Dolayısıyla, uygulamanızda bu nerede olursa olsun, "gerçek" EKL kontrollerini eklemek için iyi bir yer olabilir:
Komutun yeri belirlendi ve ACL'nin onunla başa çıkabilmesi için onun kimliğini oluşturabiliriz. Bir kullanıcı için komuta izin verilmemesi durumunda, komut çalıştırılmayacaktır (eylem). Belki dava için a CommandNotAllowedResponse
yerine CommandNotFoundResponse
somut bir emir üzerine bir talep çözümlenememiştir.
Somut bir HTTPRequest'in eşlemesinin bir komutla eşlendiği yere genellikle Yönlendirme denir . As Yönlendirme zaten komutunu bulmak için işi var, neden komut aslında ACL başına izin verildiği takdirde bu kontrol etmek uzatmak? Uzatarak Örneğin Router
bir ACL farkında yönlendiriciye: RouterACL
. Yönlendiriciniz henüz bilmiyorsa User
, o zaman Router
doğru yer değildir, çünkü ACL'nin çalışabilmesi için yalnızca komutun değil, kullanıcının da tanımlanması gerekir. Yani burası değişebilir, ancak genişletmeniz gereken yeri kolayca bulabileceğinizden eminim, çünkü burası kullanıcı ve komut gereksinimlerini karşılayan yerdir:
User -> Browser -> Request (HTTP)
-> Request (Command)
Kullanıcı başından beri kullanılabilir, Komut önce ile Request(Command)
.
Bu nedenle, ACL kontrollerinizi her komutun somut uygulamasına koymak yerine, önüne yerleştirirsiniz. Herhangi bir ağır modele, sihre ya da her neyse, ACL işini yapar, kullanıcı işini yapar ve özellikle komut işini yapar: Sadece komut, başka bir şey değil. Komutun, bir yerde korunup korunmadığını, rollerin kendisine uygulanıp uygulanmayacağını bilmekle hiçbir ilgisi yoktur.
Bu yüzden sadece birbirine ait olmayan şeyleri ayrı tutun. Tek Sorumluluk İlkesinin (SRP) biraz farklı bir ifadesini kullanın : Bir komutu değiştirmenin tek bir nedeni olmalıdır - çünkü komut değişmiştir. Şimdi başvurunuzda ACL'ing'i tanıttığınız için değil. Kullanıcı nesnesini değiştirdiğiniz için değil. Bir HTTP / HTML arayüzünden bir SOAP veya komut satırı arayüzüne geçiş yaptığınız için değil.
Sizin durumunuzdaki ACL, komutun kendisine değil bir komuta erişimi kontrol eder.
if($user->hasFriend($other_user) || $other_user->profileIsPublic()) $other_user->renderProfile()
Şöyle bir şey söylemez miydiniz (aksi takdirde, "Bu kullanıcının profiline erişiminiz yok" mu yoksa bunun gibi bir şey mi?