Nedaří se rozchodit statické ACL

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
mr.mac
Člen | 87
+
0
-

Můžete mi prosím poradit se statickým ACL (viz mnohé diskuse na tomto fóru), jsem bohužel „na začátku“ a nedaří se. Mám třídu ACL dle tutoriálu na tomto webu a nedaří se mi ověřit po přihlášení uživatele, zda jeho role isAlowed, skončím s chybou, že role „ABC“ does not exist, zde:

if (!$user->isAllowed($this->name, $this->action)) {

Je to tím, že role, resources i privileges nejsou ze statické ACL načteny, přitom mám v config.neon službu autentizatoru definouvanou.
Kdy se tedy ACL načítá? V jaké části aplikace? Mě se totiž načte až po, ale potřebuji před prvním použitím isAllowed.

Díky za rady.

Filip Procházka
Moderator | 4668
+
0
-

Jak to funguje

Pokud na ACL používáš Nette třídu Nette\Security\Permission, tak ta se registruje jako služba authorizator. Najdeš ji v DI Containeru, nebo v presenteru $this->context->authorizator.

Zajímat tě bude u Permission tato stránka v dokumentaci.

Prvně tedy uživatele přihlásíš. V presenteru zavoláš Nette\Http\User::login() s údaji (z formuláře), User řekne službě authenticator (pozor, neplést authorizator, který spravuje oprávnění a authenticator, který ověřuje identitu), že chce ověřit uživatele. Tato služba ho ověří a vrátí identitu Nette\Security\Identity. Identita obsahuje identifikátor uživatele, jeho role a nějaká dodatečná data (adresa, email, …). Třída User si tuto Identitu uloží do Session a při dalších požadavcích už je k dispozici.

Když se teď zeptáš třídy $user->isAllowed($resource, $privilege), tak se nejprve zeptá identity, jaké má role a potom se ptá authorizatoru, jesti je to pro tu roli povolena privilege pro resource.

Jak to zprovoznit

Čili tebe zajímají dvě služby:

  • authenticator: Ověří uživatele a vrátí identitu. Tento si implementuješ sám (pokud nepoužíváš Nette\Database). Mělo by ti ale stačit doladit si implementaci v sandboxu
  • authorizator: Na tento je vhodné si vytvořit nějakou továrnu (ať už taháš informace z databáze, nebo máš ACL definováno staticky. Zjednodušeně takto:
class AuthorizatorFactory extends Nette\Object
{
	public function create()
	{
		$permission = new Nette\Security\Permission;
		// ... nastavení podle dokumentace

		return $permission;
	}
}

Přidáš do configu

services:
	authenticator:
		class: Authenticator
		arguments: [@connection]

	authorizatorFactory:
		class: AuthorizatorFactory
		# arguments: [@connection]
		# tady by jsi mu mohl pro konstruktor předat
		# připojení do databáze, pokud by jsi ACL měl v db

	authorizator:
		factory: [@authorizatorFactory, create]

A třída User už si to sama převezme a zpracuje.

mr.mac
Člen | 87
+
0
-

HosipLan napsal(a):

Jak to funguje

Díky moc za velmi vyčerpávající popis. Prozatím letmo přečteno si nemyslím, že jsem někde udělal extrémní chybu. Authorizator i Autenticator mám v config.nette spuštěny v sekci services takto (namespace zatím moc nevyužívám):

model:
	class: Model
	arguments: [@database]
authenticator:
	factory: [@model, createAuthenticatorService]
authorizator:
	class: Acl

Myslel jsem si to, že by to takto nějak mělo fungovat, problém je, že před prvním testem isAllowed jsou roles a resoucres z Acl třídy nenaplněný a tudíž systém hlásí, že role ABC neexistuje. Ještě to jednou projdu a pokusím se na to přijít. Je pravda, že návod (tuším od srigi-ho mj. pro nette 0.9 a já jedu na 2.0 + PHP 5.3) jsem musel dost silně modifikovat.

mr.mac
Člen | 87
+
0
-

Tak jsem to už rozchodil, musel jsem do SecuredPresentatoru dát instanci třídy ACL:

use	Nette\Http\User;

abstract class SecuredPresenter extends BasePresenter
{
	public function startup()
	{
		parent::startup();

		$user = $this->getUser();

		$acl = new Acl;
		$user->setAuthorizator($aacl);
	...
)

Nemyslím si, že to je moc košer, asi není v pořádku services: authorizator: class Acl v config.neon.

EDIT: Nakonec jsem to udělal dle rady HosipLana a chodí to výborně, není nad to si nechat dobře poradit. Ještě jednou díky moc.

Editoval mr.mac (21. 10. 2011 10:00)

Filip Procházka
Moderator | 4668
+
0
-

Tohle není moc ideální… Proč jsem ti asi psal, jak to nastavit v configu? :)

Pokud to nechceš v configu (taky tam nerad píšu služby), tak bych doporučil spíš podědit Nette\Configurator.

class MyConfigurator extends Nette\Configurator
{
	public static function createServiceAuthorizator(Nette\DI\Container $container)
	{
		return new Acl();
	}
}

Uložíš třeba do app/models/MyConfigurator.php. V boostrap pak musíš třídu načíst „ručně“, protože robotLoader se musí spustit až po Configuratoru.

...
require_once __DIR__ . "/models/MyConfigurator.php";
$configurator = new MyConfigurator();
// $configurator = new Nette\Configurator();

$configurator->loadConfig(__DIR__ . '/config.neon');
..

Configurator si projde všechny svoje metody, které začínají na createService (zbytek je název, jako u komponent v presenteru) a přidá je jako továrničky do DI Containeru. Takže si můžeš přidávat klidně vlastní služby takto. V argumentu metody můžeš přijmout Nette\DI\Container a vytáhnout si z něz parametry, nebo závislosti. Příklad: https://github.com/…igurator.php

Editoval HosipLan (21. 10. 2011 9:31)

mr.mac
Člen | 87
+
0
-

HosipLan napsal(a):

Tohle není moc ideální…

Tato varianta je asi nejlepší. Ještě jednou díky za cenné rady.

srigi
Nette Blogger | 558
+
0
-

Hosiplan viem, ze je to trocha provokativne, ale nedavalo by vacsi zmysel upravit povodny tutorial, nech nemusis radit ludom 100x? Myslel som, ze wiki forma webu sluzi tomuto, ale v nasej komunite to vobec nefunguje. Nechapem preco.

Editoval srigi (21. 10. 2011 20:52)

Filip Procházka
Moderator | 4668
+
0
-

Pravda, moc to nefunguje. Ale nechci na to sahat, kdybych to psal já tak bych to klidně upravil…

22
Člen | 1478
+
0
-

@HosipLan: jaká výhoda je dědit od configuratoru a ne až od DI kontajneru, kam injektnu akorat služby, které potřebuji pro modely a ty mají potom svůj vlastní kontext, jako třeba connection apod.? Sice mám 2 kontexty, ale zapíšu $this->model->acl. Minimálně se mi to zdá lepší než tady hojně používaný modelLoader imho.

Filip Procházka
Moderator | 4668
+
0
-

22 napsal(a):

@HosipLan: jaká výhoda je dědit od configuratoru a ne až od DI kontajneru

Když dědím od Configuratoru a definuju služby tam, tak si nesviním třídu, do které to evidentně nepatří.

, kam injektnu akorat služby, které potřebuji pro modely a ty mají potom svůj vlastní kontext, jako třeba connection apod.? Sice mám 2 kontexty, ale zapíšu $this->model->acl. Minimálně se mi to zdá lepší než tady hojně používaný modelLoader imho.

Vůbec jsem tě nepochopil :)