Řešení autorizace pomocí anotací

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

Ahoj, potřeboval bych poradit, resp. navést správným směrem, jak ověřovat pomocí anotací před metodou, zda k ní má uživatel oprávnění, pokud ne, vyhodit vyjímku. Docela by mi to ušetřilo práci, protože psát na začátku každé funkce „if..“ a celou podmínku je dosti zdlouhavé a vím, že by to pomocí těch anotací mělo jít. Díky

Filip Procházka
Moderator | 4668
+
0
-

https://doc.nette.org/…oli-a-zdroju a krmit to ze presenter::startup()

Editoval HosipLan (26. 10. 2010 11:15)

pekelnik
Člen | 462
+
0
-

ty anotace ještě nefungujou bo se pletu?

Filip Procházka
Moderator | 4668
+
0
-

nepleteš, ještě nejsou ve FW

crempa
Člen | 198
+
0
-

Zdar, nejaka zmena v tomto smeru? Neco sem tusim videl v motivacnim videu pro tehda jeste 1.0 verzi, ale ani v posledni alpha verzi nemuzu nic o @roles @allowed apod. najit. Existuje nejaka moznost jak si to aspon pripravit nez to bude zverejneno?

Mikulas Dite
Člen | 756
+
0
-

Tak můžeš zatím zaimprovizavat, třeba použít něco ve stylu tohohle (to jsem si psal nedávno, když jsem chtěl zkusit, jak je/není dlouhé):

class AnnotationRoles extends BaseModel
{

	public static function verify($class, $method)
	{
		$roles = self::getRoles($class, $method);

		if ($roles === FALSE) {
			return FALSE;
		}

		if (!\is_array($roles)) {
			$roles = array($roles);
		}

		foreach (\Nette\Environment::getUser()->getRoles() as $role) {
			$key = array_search($role, $roles);
			if ($key !== FALSE) {
				unset($roles[$key]);
			}
		}

		return count($roles) === 0;
	}



	private static function getRoles($class, $method)
	{
		try {
			$class = new \Nette\Reflection\ClassReflection($class);
			$method = $class->getMethod($method);
			return $method->getAnnotation('secured');

		} catch (\ReflectionException $e) {
			return FALSE;
		}
	}
}

kde class má vyžadovat instanci presenter, to jsem tam zapomněl… Plus nějaká kontrola, jesli tam je ta metoda atp., ale to už nechám na tobě.

a kontrola v Protected / BasePresenteru

	public function startup()
	{
		parent::startup();

		if (!\Nette\Environment::getUser()->isLoggedIn()) {
			$this->target = ':' . $this->getName() . ':' . $this->action;
			$this->redirect('Sign:in', array('target' => $this->target));
		}

		$action = 'action' . ucfirst($this->action);
		if (!\Model\AnnotationRoles::verify($this->presenter, $action)) {
			$this->flashMessage('You don\'t have enough priviledges to do this.');
			$this->redirect('Board:');

		} else {
			$this->flashMessage('debug: you have passed verification');
		}
	}

asi by to šlo napsat i lépe? Čekám, že hlavně ta část zjišťování annotací té akce.

Funguje to podle očekávání, tzn u akce jsou ty patřičné annotace (u renderu se nepočítají).

tomees
Člen | 59
+
0
-

Mikulas Dite napsal(a):

to je pěkné řešení.. ale právě řeší jen ohlídání akcí.. kdežto já bych třeba potřeboval nějak anotacemi kontrolovat a callback metodu po odeslání formuláře atd.. a to zatím bohužel nikdo (pokud vím) dohromady nedal :-(

Mikulas Dite
Člen | 756
+
0
-

Už ti rozumím. No v tom případě můžeš rozšířit form (appform) a tam volat ten verify. Nebo, což je overkill, můžeš vylepšit __call (a asi i __invoke) a volat to verify() tam.

srigi
Nette Blogger | 558
+
0
-

@tomes toto sa holt bude musiet napisat o uroven vyssie ako Presenter. Dlho som nevidel kod Nette\Application, ale niekde tam je ukryte tzv. dispatchnutie requestu. To sa bude musiet prekryt vlastnou metodou a do nej tu logiku zaniest.

tomees
Člen | 59
+
0
-

na mě konkrétně je toto zatím moc složité, než někdo něco podobného implementuje, nebo aspoň nastíní nějaké více konkrétní řešení, vystačím si s if(isAllowed… je to sice furt dokola a může se vloudit chybka, ale svůj účel to zatím splní :-)

tomees
Člen | 59
+
0
-

@Mikulas Dite nebo by mě ještě zajímalo, zda se dá nějakým podobným způsobem ošetřit i volání signálů?

srigi
Nette Blogger | 558
+
0
-

@tomes volanie signalov je mozne takto riesit, vid. zivotny cysklus Presentera. Len si musis dopisat nieco ako vytiahnutie nazvu volanej handleMetody a jeho predanie do Model\AnnotationRoles::verify()

jtousek
Člen | 951
+
0
-

@tomees: Už jsem to, o čem mluvíš pomocí anotací řešil. Mohu se zeptat, u jakých metod potřebuješ předem ověřit zda uživatel má dostatečná práva? jsou to akce presenteru, metody modelu nebo něco jiného?

Dále bych se chtěl zeptat ostatních na ty chystané anotace v Nette… Co si mám představit pod @roles? Že v anotaci definuju, které role mají na tuto akci právo? Pokud jo, pak mi uniká smysl – typicky chci, aby si administrátor pomocí GUI sám nadefinoval role (tedy jaká role co může a nemůže), které potom bude uživatelům přidělovat, takhle napevno to není vůbec žádný posun od pevné definice rolí pro objekt Permission. Co mi uniká?

Editoval jtousek (23. 11. 2010 22:44)

srigi
Nette Blogger | 558
+
0
-

@jtousek Vsak ono sa to nijak nevylucuje. Oznacis nejaku metodu stylom allowedByShopManager (napr. odobratie produktu) a ty tu rolu iba dynamicky priradis nejakemu userovi.

Asi si to myslel opacnou logikou – nie user by mal dynamicky zoznam roli, ale chranena metoda (allowedByShopManager, allowedByAdmin, allowedByEmployye). Ked sa ale nad tym zasmyslis, zistis, ze nie metoda, ale skutocne user ma byt tym dynamickym prvkom v app.

IMHO :)

Mikulas Dite
Člen | 756
+
0
-

@jtousek:
Předně doufám, že roles je jenom dočasný název (přestože i David ho na webexpu měl v prezentaci), mnohem výmluvnější je třeba secured. To jenom tak na okraj.

Roles by (podle mě) měli spíš znamenat výčet rolí, které jsou pro danou akci (metodu) potřeba. Tzn and místo or. Máš pravdu, že dynamické acl v tom udělat nejde, ale stejně nemáš kam v dynamickém obsahu ty anotace psát. Dokážu si ale představit situaci, kde administrace (hardcoded obsah) je ověřován pomocí anotací a ostatní práva řešena jinde, resp. jinak.

Edit: @srigi:
To ale nefunguje, pokud jsou dynamicky i ty role, tzn. employee, boss, admin nejsou hardcoded, nebo je potřeba přidat další skupinu.

Editoval Mikulas Dite (23. 11. 2010 22:57)

jtousek
Člen | 951
+
0
-

@srigi promin ale nemyslím, že jsi pochopil, co jsem měl na mysli (Mikulas Dite ano)… Nechci dynamicky přiřazovat role (tedy samozřejmě že jo, ale o to teď nejde), chci ty role dynamicky vytvářet a i měnit. Tzn. pro každou akci nechci mít ani tak výčet potřebných rolí, jako spíše výčet potřebných oprávnění.

Nyní to řeším tak, že název presenteru odpovídá resource a každá akce jeho odpovídá stejnojmenému privilege. Tedy pokud uživatel chce provést např. akci Category:update, musí mít oprávnění update nad zdrojem category. Bez ohledu na to, od které role toto oprávnění zdědil. Samozřejmě některé akce žádná oprávnění nepotřebují (např. zobrazení přihlašovacího formuláře), to řeším pomocí anotace @privilege false (lze mít buď u dané akce, nebo rovnou v anotacích presenteru pro všechny akce presenteru).