Permission

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

Zdravim

Jsem nucen predelat prava ve sve app a tak se prokousavam Nette\Security\Permission a podobne.

Bohuzel postradam pro me jednu dulezitou vec. Rad bych ziskat seznam roli (skupin), ktere vsechny maji na urcenem zdroji urcita prava (provadet urcitou akci). Nejak se mi ale nedari zorientovat se. Nebo spise mi prijde, ze to Permission neumi:( Neresil jste to nekdo? Pls nasmerovat kudy kam.

Dale jeste jedna drobnost. Rekneme mam 3 role:

  • Admin – muze vse cist/editovat/mazat
  • Vedouci – muze cist/editovat/mazat pouze svoje data a cist udaje podrizenych (role zamestnanci)
  • Zamestnanci – muze cist/editovat/mazat pouze svoje data

Nejak me nenapada schudne reseni jak to napasovat na Permission. Jedine co me napada, je udelat u prav napr ‚cist:Zamestnanci‘ (popripade pomoci ID ci tak nejak), coz by vyresio otazku zda k danemu zaznamu mam ono pravo (pravo:majitelovaRole). Bohuzel to ale neresi problem SELECTu z DB, pro ktery bych potreboval seznam roli, ktere mohu zaznamy cist. Reseni nacist vse a po jednotlivych zaznamech se ptat zda mam pravo cist a popripade nezobrazit neni optimalni.

Dekuji za rady/napady:))

Jod
Člen | 701
+
0
-

To o čom hovoríš mám riešené v presenteri takto.

<?php

class Admin_News_DefaultPresenter extends Admin_BasePresenter
{
	function startup()
	{
		parent::startup();
		$this->model = new NewsModel();
	}

	function beforeRender()
	{
		$this->changeView('default');
		$this->template->add = $this->isAllowed('write');
		parent::beforeRender();
	}

	function actionDefault()
	{
		if($this->isAjax()) {
			$this->template->popupControl = null;
			$this->invalidateControl('popup');
		}
		// Filter
		$filter = new Filter($this, 'filter', $this->model->definition['News']);

		$this->template->filter = $filter;

		// DataGrid
		$grid = new DataGrid($this, 'grid');

		$where = array('languageId=%i', Environment::getVariable('languageId'));
		if($this->isAllowed('owner'))
			array_push($where, ' AND userId=%i', $this->user->identity->id);

		$grid->bindDataTable(dibi::getConnection(), 'News', $where);
		$grid->setFilter($filter->getWhere());
		$grid->setDefinition($this->model->definition['News']);
		$grid->setHiddenColumns(array('id'));

		if($this->isAllowed('read')) {
			$grid->addLink('title', 'detail', 'id');
			$grid->setRowLink('detail', 'id');
		}
		elseif($this->isAllowed('write')) {
			$grid->addLink('username', 'edit', 'id');
			$grid->setRowLink('edit', 'id');
		}

		$this->template->grid = $grid;
		if($filter->isSubmitted())
			$grid->invalidateControl();
	}

	function actionDetail($id)
	{
		$data = $this->model->getNewById($id);
		$allowed = false;
		if($this->isAllowed('owner') && $this->user->identity->id == $data['userId'])
			$allowed = true;
		elseif($this->isAllowed('read'))
			$allowed = true;
		if($allowed) {
			$detail = new DetailView($this, 'detail');
			$detail->setDefinition($this->model->definition['News']);
			$detail->setData($data);
			if($this->isAllowed('write'))
				$detail->addButton(array('Upraviť', 'edit', 'id'));
			$this->template->popupControl = $detail;
			$this->invalidateControl('popup');
		}
	}

	function actionAdd()
	{
		if($this->isAllowed('write')) {
			$form = $this->newsForm();
			$form->setDefaults(array('active' => 1));
			$this->template->popupControl = $form;
		}
	}

	function actionEdit($id)
	{
		$values = $this->model->getNewById($id);
		if(($this->isAllowed('write') && !$this->isAllowed('owner')) ||
			($this->isAllowed('write') && $this->isAllowed('owner') && $this->user->identity->id == $values['userId'])) {
			$form = $this->newsForm(true);
			$form->setDefaults($values);
			$this->template->popupControl = $form;
		}
	}

	// ...
?>

Práva mám Read, Write, Owner.

Read – dostane sa len do detailu

Read, Owner – dostane sa len do detailu svojich

Write – môže pridávať a upravovať

Write, Owner – môže pridávať a upravovať len svoje

====

Tak by ti to mohlo ísť ni? Bo podľa toho čo si popísal tak nejak to používam aj ja.

V jednej aplikácii mám riešene takto práva napevno pre role Administrátor a maklér.

V cms mám toto riešene dynamicky a všetko mi zatiaľ funguje.

Ondrej
Člen | 110
+
0
-

phx napsal(a):

Zdravim

Bohuzel postradam pro me jednu dulezitou vec. Rad bych ziskat seznam roli (skupin), ktere vsechny maji na urcenem zdroji urcita prava (provadet urcitou akci).

Permission vraci jestli ma pravo na objekt, nikoliv na konkretni zaznam v objektu.
Vedouci ma pravo mazat, ale jen v pridade, ze je vlastnik. Resil bych to rozsirenim Permission::isAllowed o dalsi parametr, kde by se predal konkretni zaznam.
Neni mi jasne co presne potrebujes.

Vypsat vsechny zaznamy, ktere ma vedouci pravo cist?

SELECT * FROM objekt
JOIN users u ON u.id = objekt.owner
LEFT JOIN users u2 ON u2.id = u.vedouci
WHERE objekt.owner = $USER_ID OR u2.id = $USER_ID
/*za predpokladu, ze zamestnanec ma pouze jednoho vedouciho*/

Zobrazit ikonku pro smazani v seznamu, kde vidi vsechny, ktere muze cist?

foreach($records as $record) {
  $canDelete = $user->isAllowed('objekt', 'smazat', $record)
}
Ondřej Brejla
Člen | 746
+
0
-

Jod napsal(a):

To o čom hovoríš mám riešené v presenteri takto.

Imho to ověřování by se mělo řešit už v modelu. Tedy pokud se bavíme o vypisování novinky podle id… modelu řeknu

<?php
$this->model->getNewById($id);
?>

a ten mi buď vrátí tu onu novinku, na kterou se ptám, protože na ní mám práva, nebo třeba vyhodí výjímku, že jsem chuligán, a že na ní právo nemám.

Pokud řešim vypisování všech novinek (ať už právo mám či ne) s tím, že vedle nch mám odkazy na edit případně delete, tak to bych zas řešil až v šabloně. Třeba podobnym způsobem, jako je ve fifteen řešený „isClickable“ políčko.

Tak to teda vidím já, je možné, že naprosto špatně :)

Každopádně do Nette\Security\Permission jsem ještě nekoukal, takže netušim jak se s tím pracuje.

Jod
Člen | 701
+
0
-

Tak ja to mám všetko na jednom mieste v presenteru a riešim to na úrovni prístupu k view. Rovnako prístup k modulu je možné riešiť len na úrovni presenteru, tak to chcem mať na jednej kope prehladne.

Ondřej Brejla
Člen | 746
+
0
-

Jasně je mi to jasný. Já jsem spíš pro, řešit to v modelu…takhle ti na ta data může sahat jakýkoliv objekt ať už práva má, nebo ne…pokud práva pořešim v modelu, tak vždy dostanu jen to, na co mám práva. Ale když jsi zvyklý to takhle řešit, tak proč ne :)

Jod
Člen | 701
+
0
-

Na data mi môže sahať len objekt ktorý pustím do podmienky.

Ondřej Brejla
Člen | 746
+
0
-

phx napsal(a):

Zdravim

Jsem nucen predelat prava ve sve app a tak se prokousavam Nette\Security\Permission a podobne.

Teď mě jen tak napadlo, po zběžném přečtení dokumentace…zdědit Permission, překrýt allow a deny a udržovat si tu strukturu v nějakym úložišti, třeba poli. Implementovat getRolesByResourceAndRules($resource, $rules);

Je to jen nápad…:)

Editoval Warden (15. 1. 2009 13:02)

phx
Člen | 651
+
0
-

Warden napsal(a):

Teď mě jen tak napadlo, po zběžném přečtení dokumentace…zdědit Permission, překrýt allow a deny a udržovat si tu strukturu v nějakym úložišti, třeba poli. Implementovat getRolesByResourceAndRules($resource, $rules);

Asi to bude jedina moznost, protoze Permission to samotne neumi:( Bohuzel co jsem koukal, je to moc slozity kod a nejak jsem do nej jeste nepronikl.

Co potrebuji?

  1. ziskat seznam roli, ktere muzou s danym zdrojen neco provadet. Rekneme proto abych jim poslal info mail, ze se neco zmenilo.
  2. Hiearchii Admin->Vedouci->Zamestanec.
    • Admin neni problem – muze vse.
    • Zamestanenec taky neni problem – muze jen na svoje data
    • Vedouci – muze na svoje + cteni dat Zamestnanecu to je problem.
phx
Člen | 651
+
0
-

Jen tak mimo:

V domumentaci je naznacneo, ze role muze mit 1 a vice rodicu, od kterych dedi prava. Rekneme ze budu mit 2 rodice. Jeden ma akci zakazanou, ale druhy ji ma povolenou. Jaka budou prava potomka? Co se preferuje? Povoleni nebo zakazani?

Ondřej Brejla
Člen | 746
+
0
-

phx napsal(a):

Jen tak mimo:

V domumentaci je naznacneo, ze role muze mit 1 a vice rodicu, od kterych dedi prava. Rekneme ze budu mit 2 rodice. Jeden ma akci zakazanou, ale druhy ji ma povolenou. Jaka budou prava potomka? Co se preferuje? Povoleni nebo zakazani?

Dědí se hierarchicky, takže imho politika posledního platného…pokud vím, tak nejde dědit od dvou předků najednou (C++), takže nevznikne problém nekompatibility dvou práv na stejné úrovni…

Přímo možno dědit pouze z jednoho předka, kterému pak můžu práva překrýt svými nově definovanými, tak to chápu já.

phx napsal(a):

Co potrebuji?

  1. ziskat seznam roli, ktere muzou s danym zdrojen neco provadet. Rekneme proto abych jim poslal info mail, ze se neco zmenilo.
  2. Hiearchii Admin->Vedouci->Zamestanec.
    • Admin neni problem – muze vse.
    • Zamestanenec taky neni problem – muze jen na svoje data
    • Vedouci – muze na svoje + cteni dat Zamestnanecu to je problem.

Resources: zamestnanecke_clanky, vedouci_clanky, admin_clanky

Rules: add, edit, delete

Roles: Zamestnanec(allow – zamestnanecke_clanky: add, edit, delete) <|--- Vedouci(allow – vedouci_clanky: add, edit, delete; deny – zamestnanecke_clanky: edit, delete) <|--- Admin(allow – NULL: add, edit, delete)

(<|--- čti extends :)

Takhle to asi nějak myslíš, ne? Možná :)

Editoval Warden (15. 1. 2009 15:02)

phx
Člen | 651
+
0
-

Warden napsal(a):

Dědí se hierarchicky, takže imho politika posledního platného…pokud vím, tak nejde dědit od dvou předků najednou (C++), takže nevznikne problém nekompatibility dvou práv na stejné úrovni…

Nemas pravdu:(

$acl = new Permission();
$acl->addRole('guest');
$acl->addRole('registered', 'guest');
$acl->addRole('administrator', 'registered');
$acl->addRole('phx', array('guest', 'registered'));

echo '<pre>';
print_r($acl);

Vystup:

[roles:protected] => Array
        (
            [guest] => Array
                (
                    [parents] => Array
                        (
                        )
                    [children] => Array
                        (
                            [registered] => 1
                            [phx] => 1
                        )

                )
            [registered] => Array
                (
                    [parents] => Array
                        (
                            [guest] => 1
                        )
                    [children] => Array
                        (
                            [administrator] => 1
                            [phx] => 1
                        )

                )
            [administrator] => Array
                (
                    [parents] => Array
                        (
                            [registered] => 1
                        )
                    [children] => Array
                        (
                        )
                )
            [phx] => Array
                (
                    [parents] => Array
                        (
                            [guest] => 1
                            [registered] => 1
                        )
                    [children] => Array
                        (
                        )
                )

Role phx ma 2 rodice. A ted babo rad. Coz me privadi k veci, ze v dokumentaci alternativni zapis neni tak zcela alternativni, ale dosahne se kapku jineho vysledku:(

Jinak diky, neco podobneho jsem ohledne prav Vedouciho take vymyslel.

  • obude jeden zdroj: napr clanky
  • opravneni: ctiSvoje, ctiPodrizenych, ctiVse (edit…)
  • reseni: pri ctiPodrizenych musim ziskat seznam vsechn roli (rekurzivne), od kterych ma prava dedim. Pak uz to neni problem:)

Nakonec tedy zbyva uz jen ten seznam roli, ktere maji nejake pravo k danemu zdroji. HELP:)

Ondřej Brejla
Člen | 746
+
0
-

Nezkoušel jsem to, jen jsem uvažoval, jak by to bylo logické :)

Zápis

<?php
$acl->addRole('phx', array('guest', 'registered'));
?>

Mně to přijde nelogický…dokonce bych ho třeba i zakázal a celou funkčnost bych nechal jednoduše takovou, jak jsem popisoval – možnost dědit pouze od jednoho předka s možným překrýváním práv, pak by nevznikaly zbytečné problémy. Co si o tom kdo myslí?

Nakonec tedy zbyva uz jen ten seznam roli, ktere maji nejake pravo k danemu zdroji. HELP:)

Jak jsem říkal, nějaké pole…rozdělený na 3 vrstvy, teď jsme línej vymýšlet kód :) Třeba:

clanky -> [edit -> (Role 1, Role 2),
           delete -> (Role 3)]
zdroj ->  [add -> (Role 1),
           delete -> (Role 1, Role 2)]

Pak implementovat tu fci, která z toho pole ta data vytáhne. Podle zdroje a práv. Snad ti to trošku pomůže :)

vlki
Člen | 218
+
0
-

Warden napsal(a):

Mně to přijde nelogický…dokonce bych ho třeba i zakázal a celou funkčnost bych nechal jednoduše takovou, jak jsem popisoval – možnost dědit pouze od jednoho předka s možným překrýváním práv, pak by nevznikaly zbytečné problémy. Co si o tom kdo myslí?

Neco mi rika, ze je tam vyssi vaha u pravidla deny, takze pokud dojde ke konfliktu, vyhraje. Ale nejsem si tim jisty.

Kazdopadne bych nemazal. Praktickou vyuzitelnost vidim v definovani ruznych roli napr. v ramci modulu. Osoba s pristupem do vice modulu tak bude dedit vice prav (zde napr. jednu roli z kazdeho modulu).

phx
Člen | 651
+
0
-

Nekdy to otestuju, co ma vetsi prioritu.

Nakonec tedy zbyva uz jen ten seznam roli, ktere maji nejake pravo k danemu zdroji. HELP:)

Ja vim co chci a celkem i tusim jak se k tomu dobrat, ale nejak jsem se nezorientoval uvnit objektu Permission abych to z nej vydoloval.

Ondřej Brejla
Člen | 746
+
0
-

vlki napsal(a):

Neco mi rika, ze je tam vyssi vaha u pravidla deny, takze pokud dojde ke konfliktu, vyhraje. Ale nejsem si tim jisty.

Kazdopadne bych nemazal. Praktickou vyuzitelnost vidim v definovani ruznych roli napr. v ramci modulu. Osoba s pristupem do vice modulu tak bude dedit vice prav (zde napr. jednu roli z kazdeho modulu).

Vim co myslíš, chápu…ale osobně mi to přijde zbytečně matoucí. Radši bych to zachoval co nejvíc simple a průhledné a takovýhle problém řešil možná nějakou super rolí, mezimodulovou…to mě jen teď napadlo, když jsem přišel vymrzlej z venčení psa, takže promyšlený to nemám ;) Ale možná by stálo za to nad tím popřemýšlet, nebo nad nějakým jiným mechanismem, který podobné věci bude řešit a přitom nebude implementovat přímě dědění od více předků, což je imho cesta do pekel…ale je to věc názoru.

phx
Člen | 651
+
0
-

Otestovano:

$acl = new Permission();
$acl->addRole('guest');
$acl->addRole('registered');
$acl->addRole('administrator', 'registered');
$acl->addRole('phx', array('guest', 'registered'));

$acl->addResource('backend');

$acl->allow('registered', 'backend', 'action');
$acl->deny('guest', 'backend', 'action');

Debug::dump($acl->isAllowed('phx', 'backend', 'action'));		// TRUE
Debug::dump($acl->isAllowed('administrator', 'backend', 'action'));		// TRUE
Debug::dump($acl->isAllowed('registered', 'backend', 'action'));		// TRUE
Debug::dump($acl->isAllowed('guest', 'backend', 'action'));		// FALSE

Takze ALLOW ma asi prednost. U dedeni to chapu. Potomek „prepise“ pravidlo rodice. V pripade vice rodicu ma ALLOW prednost.

Osobne bych dedeni nemenil:) Pouzivat to nemusis a muze se to obcas hodit:)

romansklenar
Člen | 655
+
0
-

@phx: šup s tím do dokumentace ;)

vlki
Člen | 218
+
0
-

phx napsal(a):

Takze ALLOW ma asi prednost. U dedeni to chapu. Potomek „prepise“ pravidlo rodice. V pripade vice rodicu ma ALLOW prednost.

Osobne bych dedeni nemenil:) Pouzivat to nemusis a muze se to obcas hodit:)

Tak jsem se mylil, stejne jako nema uplnou pravdu phx.

Nehraje se na zadne priority, ale opravdu na posledniho pridaneho. Viz dokumentace

Kratka demonstrace

<?php
// init
$acl = new Permission();

$acl->addRole('role1');
$acl->addRole('role2');

$acl->addResource('backend');

$acl->allow('role1', 'backend');
$acl->deny('role2', 'backend');

// priklad 1
$acl->addRole('role3', array('role1', 'role2'));

$acl->isAllowed('role1', 'backend'); // true
$acl->isAllowed('role2', 'backend'); // false
$acl->isAllowed('role3', 'backend'); // false

// priklad 2
$acl->addRole('role3', array('role2', 'role1')); // vymena poradi roli

$acl->isAllowed('role1', 'backend'); // true
$acl->isAllowed('role2', 'backend'); // false
$acl->isAllowed('role3', 'backend'); // true
?>

Hraje se tedy na vahu jednotlivych rodicu. Posledni uvedeny ma tu nejvetsi.

U phx-e jde o docela zajimavou situaci, ke ktere by – myslim – nemelo nikdy dojit. Netusim, proc by mela role phx dedit od role guest a registered zaraz, kdyz uz role registered je dite role guest, tudiz ma vse zdedene.

phx
Člen | 651
+
0
-

Uznavam, kapku prekombinovany, ale vzdal jsem 1. kod co mi prisel pod ruku na otestovani:))

Budu rad, kdyz to nekdo do te dokumentace da. Nemam prava do dokumentace a moc si v tom neverim. Obcas jsou moje vyjadreni silena.

Ondřej Brejla
Člen | 746
+
0
-

vlki napsal(a):

Hraje se tedy na vahu jednotlivych rodicu. Posledni uvedeny ma tu nejvetsi.

Tak pak je to v pořádku a snad je to dost průhledné :) Ale stejně je to imho ptákovina…protože omylem se přepíšu, změním pořadí rolí a mám problém…pokud ty role budou mít dost podobný název, tak po letmém pohledu nezjistim, že jsou špatně za sebou. Ale co už…radši vytvářet čistou strukturu, kde se tyhle featury nebudou používat :)