Hozzáférés-szabályozás (engedélyezés)
Az engedélyezés határozza meg, hogy egy felhasználó rendelkezik-e elegendő jogosultsággal például egy adott erőforrás eléréséhez vagy egy művelet végrehajtásához. Az engedélyezés feltételezi a korábbi sikeres hitelesítést, azaz azt, hogy a felhasználó be van jelentkezve.
A példákban egy Nette\Security\User osztályú
objektumot fogunk használni, amely az aktuális felhasználót reprezentálja, és amelyet függőségi injektálással történő átadással kapunk meg.
A prezenterekben egyszerűen hívjuk meg a $user = $this->getUser()
.
Nagyon egyszerű adminisztrációval rendelkező weboldalak esetében, ahol nem különböztetünk meg felhasználói jogokat,
a már ismert isLoggedIn()
módszert használhatjuk jogosultsági kritériumként. Más szóval: ha egy felhasználó
egyszer bejelentkezett, akkor minden művelethez rendelkezik jogosultsággal, és fordítva.
Szerepkörök
A szerepek célja, hogy pontosabb jogosultságkezelést biztosítsanak, és függetlenek maradjanak a felhasználónévtől.
Amint a felhasználó bejelentkezik, egy vagy több szerepet kap. Maguk a szerepkörök egyszerű karakterláncok lehetnek,
például admin
, member
, guest
, stb. Ezeket a SimpleIdentity
konstruktor
második argumentumában kell megadni, akár sztringként, akár tömbként.
Engedélyezési kritériumként most a isInRole()
metódust fogjuk használni, amely ellenőrzi, hogy a
felhasználó a megadott szerepkörben van-e:
Mint már tudjuk, a felhasználó kijelentkezése nem törli a személyazonosságát. Így a getIdentity()
metódus továbbra is a SimpleIdentity
objektumot adja vissza, beleértve az összes megadott szerepet. A Nette
Framework a „kevesebb kód, több biztonság“ elvét követi, így a szerepek ellenőrzése során nem kell ellenőrizni, hogy
a felhasználó be van-e jelentkezve is. A isInRole()
módszer hatékony szerepekkel dolgozik, azaz ha a
felhasználó be van jelentkezve, akkor az identitáshoz rendelt szerepek kerülnek felhasználásra, ha nincs bejelentkezve,
akkor egy automatikus speciális szerepkör, a guest
kerül felhasználásra.
Engedélyező
A szerepek mellett bevezetjük az erőforrás és a művelet fogalmakat is:
- A szerep egy felhasználói attribútum – például moderátor, szerkesztő, látogató, regisztrált felhasználó, adminisztrátor, …
- forrás az alkalmazás logikai egysége – cikk, oldal, felhasználó, menüpont, szavazás, előadó, …
- művelet az a konkrét tevékenység, amelyet a felhasználó a forrással végezhet vagy nem végezhet – megtekintés, szerkesztés, törlés, szavazás, …
Az engedélyező egy olyan objektum, amely eldönti, hogy egy adott szerep jogosult-e egy bizonyos művelet
végrehajtására egy adott forrással. Ez egy olyan objektum, amely a Nette\Security\Authorizator interfészt valósítja
meg, egyetlen metódussal: isAllowed()
:
Az authorizátort a DI konténer szolgáltatásaként adjuk hozzá a konfigurációhoz:
És a következő egy példa a használatra. Vegyük észre, hogy ezúttal nem az engedélyező, hanem a
Nette\Security\User::isAllowed()
metódust hívjuk meg, így nincs első paramétere a $role
. Ez a
metódus a MyAuthorizator::isAllowed()
metódust hívja meg szekvenciálisan az összes felhasználói szerepkörre,
és igazat ad vissza, ha legalább az egyiküknek van jogosultsága.
Mindkét argumentum opcionális, és alapértelmezett értékük mindent jelent.
Engedély ACL
A Nette az engedélyező beépített implementációjával, a Nette\Security\Permission osztállyal rendelkezik, amely egy könnyű és rugalmas ACL (Access Control List) réteget kínál az engedélyezéshez és a hozzáférés-szabályozáshoz. Amikor ezzel az osztállyal dolgozunk, szerepeket, erőforrásokat és egyedi jogosultságokat definiálunk. A szerepek és erőforrások pedig hierarchiákat alkothatnak. A magyarázathoz egy webes alkalmazás példáját mutatjuk be:
guest
: bejelentkezés nélküli látogató, aki olvashatja és böngészheti a web nyilvános részét, azaz cikkeket olvashat, kommentálhat és szavazhat szavazásokon.registered
: bejelentkezett felhasználó, aki ezen felül hozzászólásokat is írhat.admin
: cikkeket, hozzászólásokat és szavazásokat kezelhet.
Meghatároztunk tehát bizonyos szerepköröket (guest
, registered
és admin
) és
megemlítettük azokat az erőforrásokat (article
, comments
, poll
), amelyekhez a
felhasználók hozzáférhetnek, illetve amelyeken műveleteket végezhetnek (view
, vote
,
add
, edit
).
Létrehozunk egy példányt az Permission osztályból, és definiáljuk a szerepeket. Lehetőség van a szerepek
öröklődésének használatára, ami biztosítja, hogy például a admin
szerepkörrel rendelkező felhasználó
megtehesse azt, amit egy közönséges honlaplátogató (és persze többet is).
Most definiáljuk a források listáját, amelyekhez a felhasználók hozzáférhetnek:
Az erőforrások is használhatnak öröklődést, például hozzáadhatjuk a
$acl->addResource('perex', 'article')
.
És most a legfontosabb dolog. Meghatározzuk közöttük a szabályokat, amelyek meghatározzák, hogy ki mit tehet:
Mi van akkor, ha meg akarjuk akadályozni, hogy valaki hozzáférjen egy erőforráshoz?
Most, hogy létrehoztuk a szabálykészletet, egyszerűen megkérdezhetjük az engedélyezési lekérdezéseket:
Ugyanez vonatkozik a regisztrált felhasználóra is, de ő is megjegyzést tehet:
A rendszergazda mindent szerkeszthet, kivéve a szavazásokat:
A jogosultságokat dinamikusan is ki lehet értékelni, és a döntést a saját callbackünkre bízhatjuk, amelynek minden paramétert átadunk:
De hogyan oldjuk meg azt a helyzetet, amikor a szerepek és erőforrások nevei nem elegendőek, azaz szeretnénk definiálni,
hogy például a registered
szerepkör csak akkor szerkeszthet egy article
erőforrást, ha ő a
szerzője? Sztringek helyett objektumokat fogunk használni, a szerepkör lesz a Nette\Security\Role objektum és a forrás Nette\Security\Resource. A getRoleId()
illetve getResourceId()
metódusaik az eredeti karakterláncokat fogják visszaadni:
És most hozzunk létre egy szabályt:
Az ACL-t objektumok átadásával kérdezzük le:
Egy szerepkör egy vagy több más szerepkörből örökölhet. De mi történik akkor, ha az egyik ősnek engedélyezett egy bizonyos művelet, a másiknak pedig megtagadott? Ekkor a szerep súlya lép a játékba – az öröklendő szerepek sorában az utolsó szerepnek van a legnagyobb súlya, az elsőnek a legkisebb:
Szerepek és erőforrások is eltávolíthatók (removeRole()
, removeResource()
), szabályok is
visszafordíthatók (removeAllow()
, removeDeny()
). Az összes közvetlen szülői szerepkör tömbje a
getRoleParents()
visszaadja. Az, hogy két entitás örököl-e egymástól, a roleInheritsFrom()
és a
resourceInheritsFrom()
eredményt adja vissza.
Hozzáadás szolgáltatásként
Az általunk létrehozott ACL-t szolgáltatásként kell hozzáadnunk a konfigurációhoz, hogy az objektum $user
,
vagyis hogy kódban használhassuk például a $user->isAllowed('article', 'view')
. Ehhez írunk hozzá egy
gyárat:
És hozzáadjuk a konfigurációhoz:
A prezenterekben ezután ellenőrizheti a jogosultságokat például a startup()
módszerben: