Good Practice pro přihlašování/práva
- Savannah
- Člen | 30
Ahoj,
dělám s Nette teprv chvilku a řeším, jak správně řešit přihlašování a práva na určité sekce aplikace. V seriálu na zdrojáku toho moc není.
V examples/CD-Collection už něco je, ale přijde mi to příliš hardcoded (celý BasePresenter je zabezpečen identicky, bez možnosti rolí nebo veřejných sekcí. Řešení by bylo mít PublicBasePresenter < BasePresenter a PrivateBasePresenter < BasePresenter, kde jeden přihlášení vyžaduje a druhý ne. Ostatní presentery by z nich dědily. Ale stále to není příliš variabilní.
Poslední mě napadá psát na začátek každé akce presenteru autorizaci. To je ale obrovská duplikace kódu.
Zajímá mě, jestli to lze vyřešit nějak elegantně. Např. v Djangu se mi líbí struktura:
@login_required
def my_view(request):
...
nebo
@permission_required('polls.can_vote', login_url="/login/")
def vote(request):
...
a můžu ke každé akci daného view (ekvivalent k nette presenteru) nastavovat práva dle libosti.
Jak takový problém řešíte vy?
- Ondřej Mirtes
- Člen | 1536
Můžeš využít třídu Permission a do ní si nalít data z databáze + kontrolovat oprávnění každé akce ve startupu BasePresenteru :)
- Savannah
- Člen | 30
Ondřej Mirtes napsal(a):
Můžeš využít třídu Permission a do ní si nalít data z databáze + kontrolovat oprávnění každé akce ve startupu BasePresenteru :)
Jasně, ale šlo mi spíše o to napojení na Presenter. Abych nemusel v každé akce presenteru psát něco jako
public function renderFoo () {
if ($acl->isAllowed('guest', 'poll', 'vote') == false) {
$this->redirect('Auth:login', array('backlink' => $backlink));
return;
}
// continue with action
}
romansklenar napsal(a):
Něco takového není problém zařídit, mrkni se pro inspiraci zde.
jo, tohle by mohlo být to, co hledám :) Kde má tohle dokumentaci plz? Abych věděl, jak to tam pak probíhá?
- romansklenar
- Člen | 655
Nemá to nikde dokumentaci, není to součástí distribuce. Když se mrkneš
do BasePresenteru
na metodu startup()
tak se tam akorát volá kontrola, jestli
třída, handler signálu, metoda akce nebo renderer pohledu nemá anotaci
@secured
, pokud ano a uživatel není autentizován přesměruje na
presenter, kde se může přihlásit a po úspěšném přihlášení ho vrátí
na původní akci.
- Ondřej Mirtes
- Člen | 1536
Já mám v BasePresenter::startup kontrolu, zda-li má uživatel povolení pro resource (kterým je název Presenteru) a privilege (kterým je název action či signálu), pokud ne, vyhazuji BadRequestException(‚msg‘, 403) :)
- Savannah
- Člen | 30
romansklenar napsal(a):
Nemá to nikde dokumentaci, není to součástí distribuce. Když se mrkneš do BasePresenteru na metodu
startup()
tak se tam akorát volá kontrola, jestli třída, handler signálu, metoda akce nebo renderer pohledu nemá anotaci@secured
, pokud ano a uživatel není autentizován přesměruje na presenter, kde se může přihlásit a po úspěšném přihlášení ho vrátí na původní akci.
No v tom, co jsi mi posílal, je jenom
class ArticlePresenter extends BasePresenter {
protected function startup() {
$this->model = new ArticlesModel();
parent::startup();
}
ve startupu :(
Ondřej Mirtes napsal(a):
Já mám v BasePresenter::startup kontrolu, zda-li má uživatel povolení pro resource (kterým je název Presenteru) a privilege (kterým je název action či signálu), pokud ne, vyhazuji BadRequestException(‚msg‘, 403) :)
Jo, tohle zní dobře. Jenom se zeptám nette-nováčkovskej dotaz – jak zjistím v preparu presenter name a action/signal name?
Jinak přemýšlim, jestli neni lepší místo výjimky házet rovnou redirect na login presenter. Než abych pak výjimku chytal v bootstrapu a tam dělal redirect.
- Ondřej Mirtes
- Člen | 1536
Jojo, můžeš místo BadRequestException dát flash zprávičku a přesměrovat na login presenter – a po přihlášení hodit uživatele zpátky na místo, kam se snažil přistoupit :)
Název Presenteru a action – $this->getName()
a
$this->getAction()
:))
- Savannah
- Člen | 30
Tak jsem si s tím zkoušel trochu pohrát. Posílám to sem, kdyby vás to zajímalo nebo když byste mi postli, co tam mám špatně :) V Nette ještě neumím, takže jsem na spoustu věcí určitě nemyslel a pár nevím, jak udělat. Prvně nevím, jestli je ještě něco jiného než renderFoo() a handleFoo(), na co se dá z browseru pomocí url dostat. A za druhé jak správně dostat název action, kterou si uživatel vyžádal v url.
var_dump($this->getSignal());
mi vyhodí jenom
array
0 => string '' (length=0)
1 => string 'foo' (length=3)
(na index.php?do=foo). Tak jestli se mám spoléhat na to, že [1] je vždy název daného signálu nebo jak to vlastně je.
Jinak se snažím, jak už jsem psal, o něco jako má Django s anotacemi.
Url: BaseAuthPresenter / DemoPresenter
- Ondřej Mirtes
- Člen | 1536
Action získáš přes $this->getAction()
, jak jsem psal.
Metody, které se volají při přístupu k nějaké action jsou
actionName
a renderName
.
handleName
slouží ke zpracování signálu :)
- Savannah
- Člen | 30
možná mám jenom bordel v názvosloví:
mám kód
<a href="{link foo!}">xxx</a>
což teda očividně neni action
ale signal
, že?
Jak se dostanu na action
? (resp. jaký je rozdíl oproti
signal
?) A jsou ještě jiné věci než render
,
action
a signal
? (jako na co se dá dostat pomocí
URL) /vim, že sem to je asi trochu do jiné diskuse, ale píšu to sem, hodně
se to váže k tomu, čeho se snažím dosáhnout a rád bych tu problematiku
za tím pochopil/
- Ondřej Mirtes
- Člen | 1536
Klidně stačí i {link action}
(bez vykřičníku,
plink
slouží k odkazování na Presenteru
v komponentách :))
- Oggy
- Člen | 306
jenom dotaz pro inspiraci..
kam umisťujete ověření přihlášení uživatele?
dejme tomu že máme BasePresenter … kde jsou společné prvky pro
Authpresentet (ve kterém je také loginForm) a pro další Presentery ..
Do BasePresenteru? tam asi ne.. z něj dědí i Auth
a ostatní presentery také dědí z Base..ale zase to nebudeme přece psát
v každém kód na ověření znovu ..
- Ondřej Mirtes
- Člen | 1536
Do startupu v BasePresenteru. Klidně tam vyjmenuj výjimky, pro které se to ověřovat nemá.
- Ondřej Mirtes
- Člen | 1536
Záleží, co chceš, aby u tebe představovalo resource a privilege… Já mám jako resource název presenteru a privilege název action…
Nástřel:
protected function startup() {
parent::startup();
$user = $this->getUser();
if (!$user->isAllowed($this->getName(), $this->getAction())) {
if ($user->isAuthenticated()) {
throw new BadRequestException('Permission denied.', 403);
} else {
$this->flashMessage('Permission denied. Perhaps you forgot to log in.','error');
$this->redirect('Auth:', array('backlink' => $application->storeRequest()));
}
}
}
V Auth můžeš přepsat startup, to je pravda :) Ale pozor, Presenter
vyžaduje volání předka startupu, ale namísto parent::startup()
můžeš zavolat Presenter::startup()
a výjimka ti už
nevyskočí :)
Případně to můžeš zpracovat přes anotace, pokud nechceš kontrolovat všechny Presentery a všechny actiony. Příklad takové kontroly je i tu někde na fóru.
Editoval Ondřej Mirtes (7. 1. 2010 20:56)
- Oggy
- Člen | 306
Ondřej Mirtes napsal(a):
Záleží, co chceš, aby u tebe představovalo resource a privilege… Já mám jako resource název presenteru a privilege název action…
Nástřel:
protected function startup() { parent::startup(); $user = $this->getUser(); if (!$user->isAllowed($this->getName(), $this->getAction())) { if ($user->isAuthenticated()) { throw new BadRequestException('Permission denied.', 403); } else { $this->flashMessage('Permission denied. Perhaps you forgot to log in.','error'); $this->redirect('Auth:', array('backlink' => $application->storeRequest())); } } }
V Auth můžeš přepsat startup, to je pravda :) Ale pozor, Presenter vyžaduje volání předka startupu, ale namísto
parent::startup()
můžeš zavolatPresenter::startup()
a výjimka ti už nevyskočí :)Případně to můžeš zpracovat přes anotace, pokud nechceš kontrolovat všechny Presentery a všechny actiony. Příklad takové kontroly je i tu někde na fóru.
děkuju..vyčerpávající
- BigCharlie
- Člen | 283
Pochopil jsem správně, že celý naznačený postup řeší i situaci s odeslaným formulářem ve chvíli, kdy mi vyprší přihlášení (tj. neztratím data z formuláře)? Projdu si tedy kolečkem odeslání formuláře → přesměrování na login presenter – přihlášení – obnova původního požadavku (odeslání formuláře). Takže po přihlášení uvidím výsledek po odeslání formuláře?
A jak to vypadá z flash zprávami, jak se ptal kravčo? Skutečne se některé zahodí, nebo se zobrazí všechny?
- David Grudl
- Nette Core | 8218
Po přihlášení se uvidí výsledek po odeslání formuláře. Ale faktem je, že to nemusí být úplně ideální řešení z uživatelského hlediska, že by třeba lepší bylo zobrazit vyplněný formulář a nechat jej uživatelem znovu odeslat. Co myslíte?