Ako na autorizaciu pomocou anotaci

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

Caute snazim sa urobit autorizaciu pomocou anotaci. Bol by som rad keby ma niekto nakopol kto to ma riesene funkcne a ako. Ako mate riesene anotacie role, zdroje a operacie a ako to spracuvate cez checkRequirements. Zaujimalo by ma ako riesite autorizaciu na uroven metod. Napr.: na handle alebo action. Popripade na uroven komponent a ich handle. Bol by som rad za nejake nakopnutie. Pouzivan nette 2.1 dev

besanek
Člen | 128
+
0
-

Já osobně mám vlastní anotaci allowed, např. @allowed(article,delete), kterou používám buď pro celý presenter nebo action metody. Práva ověřuji jen na úrovni presenteru.

Implementaci mám nějak takto

public function checkRequirements($element) {
	$annotations = $element->getAnnotations();

	$rules = array();
	if(isset($annotations['allowed'])){
		$rules = $annotations['allowed'];
	}

	foreach($rules as $rule){
        	if(!$this->user->isAllowed($rule[0] , $rule[1])){
        		throw new \Nette\Application\ForbiddenRequestException();
		}
	}
}
Šaman
Člen | 2634
+
0
-

Já už bych nedoporučoval zkoušet přístup pomocí anotací. Na jednom projektu to mám a je s tím víc starostí, než užitku.

Pokud chceš v anotacích přímo definovat kdo kam může:

  1. oprávnění je rozházené po všech presenterech, není možné plošně nastavit/zakázat přístup
  2. v anotaci nemáš (rozumně jednoduše) k dispozici konkrétní zdroj a uživatele musíš tahat z contextu. V praxi to znamená, že nejsi schopen říct, že editovat uživatele může jenom každý sebe.

Pokud jen automatizuješ kontrolu všech akcí:

Nakonec jsem si vytvořil anotaci @secured nad celým presentrem, která mi zkontroluje alespoň statická práva na každou akci. (Jestli chceš, mohu poslat kód.) Veškerá nastavení oprávnění jsou v ACL, anotace pouze zajistí, že aktuální uživatel musí mít povolen přístup například ke zdroji „Homepage“ privilegium „default“. Jenže to kontroluje i každou komponentu a signál a ACl se mi tedy dost rozrostlo. Potřebuji pro každý presenter, pohled, komponentu a akci samostatně definovat přístup.

Navíc u zdrojů, kde chci kontrolovat jestli konkrétní uživatel má práva na tento konkrétní zdroj si to pak stejně musím překontrolovat ručně. (Tzn. anotace mi zajistí, že uživatel se dostane na editaci uživatele, ale pak si musím ručně zkontrolovat, jestli chce editovat sebe – to může – nebo někoho cizího, což nesmí.)

Navíc vzniká prostor pro WTF záseky, kdy jsem měl povolenou akci 'delete' a stále mi to zakazovalo smazat zdroj, protože jsem to volal signálem 'delete!'. V ACL to ale není tak do očí bijící a blbě se v tom hledá chyba.

⇒ příště si budu hlídat práva ručně a bude mi stačit několik málo zdrojů a oprávnění.

Editoval Šaman (14. 7. 2013 18:14)

duskohu
Člen | 778
+
0
-

@Šaman bol by som rad keby si nieco poslal, mimimalne aspon by som si pozrel funkcnu implementaciu.

Šaman
Člen | 2634
+
+3
-

Tohle mám v BasePresenteru.
Použití je takové, že každý presenter s anotací @secured si sám hlídá práva podle ACL. Nevýhody jsem už zmiňoval – musíš vytvořit zdroj podle každé komponenty a dá uživateli oprávnění submit! apod. Na této úrovni neřeším tedy přístup ke zdroji (entitě), ale k akci/handleru daného presenteru či komponenty.

<?php
/**
 * Ověření oprávnění.
 */
public function checkRequirements($element)
{
	// pokud má presenter anotaci @secured, zkontrolujeme statická oprávnění
	if ($this->reflection->getAnnotation('secured'))
	{
		// jedná se o akci presenteru
		if ($this->signal === NULL)
		{
			$resource = $this->name;
			$action = $this->action;
		}
		// jedná se o signál presenteru
		elseif ($this->signal && empty($this->signal[0]))
		{
			$resource = $this->name;
			$action = $this->signal[1] . "!";
		}
		// jedná se o signál komponenty
		elseif ($this->signal && $this->signal[0])
		{
			$resource = $this->signal[0];
			$action = $this->signal[1] . "!";
		}
		// tohle by nemělo nikdy nastat
		else
		{
			throw new InvalidStateException("Volaná akce není v presenteru, ani komponentě!");
		}

		// zkontrolujeme práva
		if (!$this->user->isAllowed($resource, $action))
		{
			$this->flashMessage('Nemáte potřebná oprávnění pro tuto akci.');
			if ($this->user->isLoggedIn())
			{
				$this->redirect('Homepage:default');
			}
			else
			{
				$this->redirect("Homepage:login");
			}
		}
	}
}
?>

V ACL mám tedy např.

<?php

/* seznam uživatelských rolí */

$this->addRole('guest');
$this->addRole('user');


/* seznam zdrojů */

#presentery
$this->addResource('Homepage');
$this->addResource('User');

#komponenty
$this->addResource('loginForm');
$this->addResource('logoutControl');
$this->addResource('registrationForm');
$this->addResource('lostPasswordForm');

/* seznam pravidel oprávnění */

# nepřihlášený uživatel smí jen na registraci a login
$this->allow('guest', 'Homepage', array('login', 'registration', 'lostPassword', 'activate!', 'lostPassword!'));
$this->allow('guest', array('loginForm', 'registrationForm', 'lostPasswordForm'), 'submit!');
?>

P.S. Nekontroloval jsem, jestli někde není potřeba doplnit namespace – ty mám všechny v use sekci. Jinak by to mělo být funkční – vykopíroval jsem to z projektu (Nette 2.1) a upravil jen specifické názvy na obecné.

Editoval Šaman (14. 7. 2013 21:55)