Permission
- phx
- Člen | 651
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
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
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
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.
- Ondřej Brejla
- Člen | 746
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 :)
- Ondřej Brejla
- Člen | 746
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
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?
- ziskat seznam roli, ktere muzou s danym zdrojen neco provadet. Rekneme proto abych jim poslal info mail, ze se neco zmenilo.
- 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.
- Ondřej Brejla
- Člen | 746
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?
- ziskat seznam roli, ktere muzou s danym zdrojen neco provadet. Rekneme proto abych jim poslal info mail, ze se neco zmenilo.
- 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
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
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
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).
- Ondřej Brejla
- Člen | 746
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
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:)
- vlki
- Člen | 218
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.
- Ondřej Brejla
- Člen | 746
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 :)