Nette Framework
  • Úvodní stránka
  • Download
  • Dokumentace
  • Fórum
  • Blog
  • Přispějte
  • Quick Start
    • Začínáme
    • Adresářová struktura
    • Vytvoření presenteru
    • Připojení šablony
    • Tvorba odkazů
    • Hezčí šablony
    • Zobrazení tabulky
    • Stránkování a řazení
    • Tvoříme komponentu
  • Nette\Annotations
  • Nette\Application
    • Application
    • AppForm
    • Control
    • Presenter
    • PresenterCompo­nent
    • PresenterRequest
    • Routování
    • MultiRouter
    • Route
    • SimpleRouter
  • Nette\Caching
  • Nette\Component
  • Nette\Debug
    • Základy
    • Logování chyb
    • Firebug
  • Nette\Environment
  • Nette\Forms
  • Nette\IO\SafeS­tream
  • Nette\Loaders
  • Nette\Object
  • Nette\Security
    • Bezpečnost aplikací
    • Identity
    • SimpleAuthenti­cator
    • Permission
    • Dynamická správa rolí a zdrojů
  • Nette\String
  • Nette\Templates
    • Template
    • Template Filters
    • Template Helpers
  • Nette\Web\Html
  • Nette\Web\HttpR­equest
  • Nette\Web\HttpR­esponse
  • Nette\Web\Session
  • Nette\Web\User
Naposledy změněno 17. 11. 2008 Edituj Historie Poslední změny

Nette\Security\Per­mission

Ověřuje práva a přístupy k objektům na základě rolí.

Nette\Security\Permission je objekt implementující rozhraní Nette\Security\IAuthorizator poskytující programátorovi lehkou a flexibilní ACL vrstvu pro řízení práv a přístupu.

Tato vrstva velmi úzce souvisí s objektem Nette\Web\User a jejím základem je definování pravidel (rules).

Autorizace (zjištění, zda má uživatel právo to či ono udělat) rozhoduje se na základě rolí (roles), zdrojů/objektů (resources) a práv/akcí (privileges), která v celé aplikaci určí kdo může přistupovat k chráněnému objektu a jaké akce s ním může vykonávat.


Lépe poslouží jako vysvětlení následující příklad webové aplikace:

  • Nepřihlášený (neautentizovaný) návštěvník webu (což je výchozí role Nette\Web\User) může číst a procházet veřejnou část webu, tzn. číst články, komentáře, novinky a volit v anketách.
  • Oproti tomu přihlášený uživatel, který je registrován může dostávat novinky mailem a komentovat.
  • Další uživatelé mají přístup k administrační části a mohou provádět úkony jako psát a spravovat své příspěvky a provádět různé změny v aplikaci (třeba změnit vzhed, záhlaví, zápatí) a mají samozřejmě i práva procházet veřejnou část a dostávat novinky mailem.

Nadefinovali jsme si tedy určité role (guest, registered a administrator) a objekty (news, article, poll, comments, backend), ke kterým mohou uživatelé s nějakou rolí přistupovat nebo provádět určité akce (view, vote, comment, feed, edit).

Jednoduše řečeno

  • role (role) je vlastnost uživatele, který může přistupovat k objektům/zdrojům
  • zdroj (resource) je objekt který je kontrolován
  • práva (privilege) jsou akce, které může s objektem provádět uživatel s rolí

Vzájemné vazby kdo co může s čím dělat ale určijí až pravidla (rules), které jsou uchovávány právě objektem Permission. Ten toho umí samozřejmě víc, než jen uchovávat pravidla.

Zároveň je tu ještě jedna vazba, možná ne na první pohled zcela zřejmá, a to dědičnost rolí, která zajistí, že uživatel s rolí administrátor může dělat i to co obyčejný návštěvník webu.

role unikátní práva rodič
guest view, vote NULL
registered feed, comment guest
administrator edit registered

Poznámka: práva administrátora lze nadefinovat i jako ‚bez omezení‘ tzn. bez rodičů od kterých by dědil nějaká omezení (viz níže).

Začínáme

Nejprve si ukážeme, jak nadefinovat objektu Permission uživatelské role.
Ještě před tím je ale třeba vytvořit instanci třídy, se kterou budeme pracovat.

$acl = new Permission();

Role (Roles)

Jak již bylo řečeno, budeme postupně vytvářet stromovou strukturu rolí, která dědí oprávění od svých rodičů.
Použijeme výše zmíněný příklad webové aplikace o třech rolích. Mějmě tedy role guest, registered a administrator.

$acl->addRole('guest');
$acl->addRole('registered', 'guest');
$acl->addRole('administrator', 'registered');

// alternativně
$acl->addRole('administrator', array('guest', 'registered'));

Docela triviální že? Tímto zajístíme, že se nám vlastnosti přenášejí z rodičovské role na potomky.
Na příkladu vidíte, že je jedno jestli jako rodiče uvedete pole nebo řetězec, objekt Nette\Security\Permission přelouská obojí.

Za zmínku stojí metoda getRoleParents(), která vrací pole se všemi rodičovskými rolemi a také metoda roleInheritsFrom(), která zjistí, zda-li od sebe dědí dvě role. Jejich použití:

$acl->roleInheritsFrom('administrator', 'guest'); // TRUE
$acl->getRoleParents('administrator'); // array('guest', 'registered')

Zdroje neboli objekty (Resources)

Nyní je čas nadefinovat i seznam objektů, ke kterým mohou uživatelé s rolemi přistupovat.

$acl->addResource('news');
$acl->addResource('article');
$acl->addResource('poll');
$acl->addResource('comments');
$acl->addResource('backend');

I zdroje/objekty mohou vytvářet stromovou strukturu.
Využítí? Napadá mě možná e-shop, kde by kategorie dědila produkt.
Metody pro manipulaci se zdroji jsou podobné jako s objekty, liší se jen názvy: resourceInheritsFrom(), removeResource() atd.

Práva a pravidla (Privileges & Rules)

A teď to nejdůležitější. Samotné role a objekty by nám byli k ničemu, musíme mezi nimi vytvořit ještě pomocí práv/akcí vazby (neboli pravidla).

// host může prohlížet obsah jen veřejné části, hlasovat v anketách
$acl->allow('guest', array('news', 'article', 'poll', 'comments'), 'view');

// předchozí příkaz alternativně ve dvou příkazech: (ale trochu přes koleno)
$acl->allow('guest', NULL, 'view');
$acl->deny('guest', 'backend', 'view');

$acl->allow('guest', 'poll', 'vote');


// registrovaný dědí právo view od hosta, ale má i právo komentovat a dostávat novinky mailem
$acl->allow('registered', 'comments', 'comment');
$acl->allow('registered', 'news', 'feed');


// ale jelikož už moc práv nezbývá, můžeme je určit i výčtem jako u předchozích tak,
// abychom mu umožnili i přístup do administrace, který jsme zamezili hostovi a registrovanému
// a na víc ke všemu dostane práva view a edit
$acl->allow('administrator', NULL, array('view', 'edit'));
$acl->allow('administrator', 'backend', 'view');

Autorizace

Nyní když máme vytvořený seznam pravidel, můžeme jednoduše provádět autorizaci.

$acl->isAllowed('guest', 'article', 'view') ? "allowed" : "denied";  // allowed
$acl->isAllowed('guest', 'article', 'edit') ? "allowed" : "denied";  // denied
$acl->isAllowed('guest', 'backend', 'view') ? "allowed" : "denied";  // denied
$acl->isAllowed('guest', 'poll', 'vote') ? "allowed" : "denied";  // allowed

// registrovaný dědí od hosta jak práva tak omezení
$acl->isAllowed('registered', 'article', 'view') ? "allowed" : "denied";  // allowed
$acl->isAllowed('registered', 'comments', 'comment') ? "allowed" : "denied";  // allowed
$acl->isAllowed('registered', 'backend', 'view') ? "allowed" : "denied";  // denied

// administrátor nemá nyní žádné omezení
$acl->isAllowed('administrator', 'poll', 'vote') ? "allowed" : "denied";  // allowed
$acl->isAllowed('administrator', 'backend', 'view') ? "allowed" : "denied";  // denied


Práva administrátora lze nadefinovat i jako ‚bez omezení‘ tzn. bez rodičů od kterých by dědil nějaká omezení. Vypadalo by to asi takto:

$acl->removeRole('administrator');  // odeberu roli z pravidel
$acl->addRole('administrator');  // vytvořím roli znova, ale bez předků
$acl->allow('administrator');  // nastavím pravidlo: všechna práva a všechny zdroje pro administrátora bez omezení

Můžete si všimnout že kdykoliv za běhu aplikace můžeme i odebrat roli. A nejenom ji, odebírat ze seznamu pravidel lze objekty: removeResource(), removeAllResources(); ale i samotná pravidla: removeAllow(), removeDeny(). Máme zde i metody na kontrolu přítomnosti nějaké role nebo objektu: needRole(), needResource(); které vyhodí výjimku InvalidStateEx­ception pokud není zjištěna jejich přítomnost.

Napojení na Nette\Web\User

Na začátku jsem zmiňoval, že celá třída Nette\Security\Permission velmi úzce navazuje na Nette\Web\User. Dá se používat zcela bez něj, ale spolu dosáhnou maximální efektivity.

Pro začátek je potřeba zaregistrovat autorizační a autentizační handler:

Environment::getServiceLocator()->addService(new MyAuthenticator, 'Nette\Security\IAuthenticator');
Environment::getServiceLocator()->addService(new Permission, 'Nette\Security\IAuthorizator');

nebo v config.ini

service.Nette-Security-IAuthenticator = MyAuthenticator
service.Nette-Security-IAuthorizator  = Permission

Autentizační handler MyAuthenticator může vypadat například takto:

class MyAuthenticator implements IAuthenticator
{
    /*
     * @param  array
     * @return IIdentity
     * @throws AuthenticationException
     */
    function authenticate(array $credentials)
    {
        // jméno, heslo i role mohou být získány třeba z databáze
        $username = 'john';
        $password = 'xxx';
        $roles    = array('admin', 'editor');

        if ($credentials['username'] !== $username) {
            throw new AuthenticationException('Unknown user', self::IDENTITY_NOT_FOUND);
        }

        if ($credentials['password'] !== $password) {
            throw new AuthenticationException('Password not match', self::INVALID_CREDENTIAL);
        }

        return new Identity('John Doe', $roles); // zde je důležité právě předání rolí
    }

}

Kdekoliv v aplikaci, nebo v nějakém vašem modelu, komponentě stačí zavolat:

// s využitím třídy Environment
$acl  = Environment::getService('Nette\Security\IAuthorizator');
$user = Environment::getUser();

// bez Environment
$acl  = new Permission;
$user = new User;

// následně naplňíme autorizační handler pravidly
$acl->addRole('editor');
$acl->addRole('admin');
$acl->addResource('file');
$acl->addResource('jany');
$acl->allow('admin', 'file', 'delete_file');
$acl->allow('editor', 'jany', 'say_hello');
$acl->deny('editor', 'jany', 'sleep_with_jany');

// pokud nepoužíváme služby použijeme k nastavení handlerů metody
$user->setAuthenticationHandler($acl);
$user->setAuthorizationHandler(new MyAuthenticator);

// samotná autorizace
$user->isAllowed('file', 'delete_file'); // TRUE
$user->isAllowed('jany', 'sleep_with_jany'); // FALSE
$user->isAllowed('jany', 'say_hello'); // TRUE

// obecně
$user->isAllowed($resource, $privilege);

Metoda isAllowed() má nyní jen dva parametry, role se sama doplní pomocí metody getRoles() a v cyklu se projdou všechny role a při prvním kladném vyhodnocení se kladně vyhodnotí i podmínka výše. To vše je již implementováno v Nette\Web\User.
U proměnné $user můžeme dále používat veškeré metody uvedené v Nette\Web\User.

Viz také:

  • Nette\Security\Per­mission API reference
  • Dynamická správa rolí a zdrojů
« SimpleAuthenti­cator Dynamická správa rolí a zdrojů »

Nette Framework powered | dibi powered | Texy! powered | Institut Školení PHP