Redirect v BasePresenteru ve startup() → Příliž mnoho přesměrování

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

Ahoj,
jsem začátečník s nette a řeším „problém“, kde potřebuju, aby při vstupu na kteroukoliv stránku aplikace, pokud enní uživatel přihlášen se provede přesměrování na Sign:in. Tak jsem si tak říkal, že bych to mohl napsat do startup() BasePresenteru:

abstract class BasePresenter extends Nette\Application\UI\Presenter{

    public function startup() {
        parent::startup();
        if(!$this->getUser()->isLoggedIn()) $this->redirect('Sign:in');
    }

}

Což ale způsobí chybu „Tato stránka obsahuje smyčku přesměrování“ – což je „možná asi“ i logický, pokud se aplikace při přesměrování znovu spouští. Když ten řádek s přesměrováním dám do Homepage:default, tak to samozřejmě funguje, ale já to potřebuju pro všechny stránky.

Jak se toto řeší, nebo co mi uniká? (po prohledávání fóra by se doporučuje to dát do startup() BasePresenteru pro „globální“ účinek)

duke
Člen | 650
+
0
-

Tvůj „globální“ účinek je až příliš globální, neboť se vztahuje i na akci Sign:in. Tu je třeba nějak vyčlenit. Buď explicitně podmínkou nebo např. tak, že SignPresenter bude dědit z jiného BasePresenteru, ve kterém tato kontrola nebude.

llsm
Člen | 121
+
0
-

Musis kontrolovat tedy i jestli jsi na prihlasovaci strance a pokud ano, tak aby se redirect neprovedl. Neco jako:

<?php
 if ((!$this->user->isLoggedIn()) && ($this->reflection->name != 'SignPresenter' && $this->getAction() != 'in')) $this->redirect('Sign:in');
?>

Dědit v urcitem presenteru od startup() v BasePresenteru bez volani parent::startup() neni mozne, tim padem to neni reseni, pokud nechces mit v aplikaci vic basepresenteru.

Editoval llsm (10. 4. 2013 14:20)

thm
Člen | 147
+
0
-

Díky za rychlou odpověď. Je to na mě moc obecně napsané.
K prvnímu způsobu: Mohl bys mi prosím nastínit, kam a jakou podmínku napsat aby se pro Sign:in neprováděla kontrola ve startup() BasePresenteru (jestli jsem to pochopil dobře?)
K druhému způsobu: Aha :) Tak si to zatím zkusím napsat pomocí dalšího BasePresenteru

hAssassin
Člen | 293
+
0
-

@thm > Dukeovo reseni je lepsi. Pokud se jedna o admina tak kor (prakticky vsechny jsou zabezpeceny krom prihlasovaciho).

Ale obecne: mas nejaky BasePresenter, z neho dedi SignPresenter (+ vsechny presentery ktere nemaji byt zabezpeceny) a BaseSecuredPresenter (z neho dedi pak vsechny ktere maji byt zabezpecene, napr. MemberProfilePresenter, apod.). No a tu tvoji podminku pak das do BaseSecuredPresenter::startup().

Jako bonus pak muzes dat i do BaseSecuredPresenter signal na odhlaseni :)

Nox
Člen | 378
+
0
-

To je asi lepší způsob, osobně používám:

[BasePresenter] → (presentery nevyžadující přihlášení)
[BasePresenter] → [SecuredPresenter] → (presentery vyžadující přihlášení)

test na autentikaci (no a i základní autorizaci) je pak prostě v SecuredPresenter::startUp(). V BasePresenteru je teda to, co je společné pro veřejné i neveřejné části.

thm
Člen | 147
+
0
-

Á výborně díky llsm za radu – toto jsem potřeboval. Já si myslel že to nějak půjde zjistit kam se snažím lézt :) Paráda.
Jinak jsem si to mezitím napsal pomocí druhého BasePresenteru a to funguje také. Ale pro pořádek (dle mého názoru) je asi lepší explicitní podmínka, kdy zjišťuju na kterém presenteru:akci jsem.
Díky Vám oběma.

thm
Člen | 147
+
0
-

hAssassin, Nox: To je pravda – to mě nenapadlo. Ostatně mě toho ještě dlouho moc napadat nebude, protože cca před měsícem jsem začal s OOP a to myšlení si ještě musím zažít.

Díky všem za rychlé reakce – je to paráda.

llsm
Člen | 121
+
0
-

hAssassin napsal(a):

@thm > Dukeovo reseni je lepsi. Pokud se jedna o admina tak kor (prakticky vsechny jsou zabezpeceny krom prihlasovaciho).

To je podle mne dost sporne. Ja vetsinu casu travim psani internich aplikaci, ktere prakticky nemaji verejnou cast, tedy krome prihlasovaciho formulare. A tam mi nejake zbesile neprehledne dedeni presenteru prijde horsi nez udelat jednu osklivou podminku, nad kterou se sice clovek neznaly pozastavi, ale vcelku brzy prijde na to, k cemu slouzi. Jinak by potreboval projit strukturu nekolika presenteru, aby se dobral k tomu, proc to funguje zrovna takhle.
Navic u slozitejsich struktur se podobne veci resi vetsinou pomoci ACL a to je pak cele jina pisnicka.

hAssassin
Člen | 293
+
0
-

@thm > sorry ale podminka je podle me cisty zlo, protoze:

  1. v podmince se ti vyskytuje primo nazev presenteru i akce, pokud se neco z toho rozhodnes menit musis upravovat nekolik souboru (prejmenovani, prepis presenteru, oprava podminky), kdezto v druhem pripade ti staci jen v prezenteru zmenit nazev tridy ze ktery dedi a je to.
  2. pokud mas jen jediny verejny presenter, tak OK, ale pokud jich mas treba vic (typicky Front je vetsina verejna, pouze par presenteru je neverejnych). To tam budes vypisovat skutecne vsechny presentery a akce? :-)

@llsm >

A tam mi nejake zbesile neprehledne dedeni presenteru prijde horsi nez udelat jednu osklivou podminku

Neprehledne dedeni? Vzdyt ti pribyde jen jediny presenter? co je na tom neprehlednyho? Naopak ta podminka je dost neprehledna protoze je zahrabana nekde v nejaky metode v nejakym souboru a to se pak tezko hleda. Navic je sama neprehledna, takze kdyz ji nekdo uvidi, rekne si „whaaat?“.

Navic u slozitejsich struktur se podobne veci resi vetsinou pomoci ACL a to je pak cele jina pisnicka.

Bacha, neplest si autentizaci (tedy overeni, zda je uzivatel prihlaseny) s autorizaci (coz dela ACL ;).

Editoval hAssassin (10. 4. 2013 16:07)

Aurielle
Člen | 1281
+
0
-

Kdyby se někomu zdála struktura BasePresenter → SecuredPresenter → FooPresenter moc komplexní, dá se to vyřešit i tak, že v SignPresenteru přetížíte metodu startup() tak, že nebude volat startup() z vašeho BasePresenteru, ale přímo z Nette\Application\UI\Presenter:

protected function startup()
{
	// preskoci volani startup() v BasePresenteru, kde je podminka pro prihlaseni
	Nette\Application\UI\Presenter::startup();
}
hAssassin
Člen | 293
+
0
-

@Aurielle > neni tohle trochu pekna prasarna? Jako fungovat to bude, ale neporusuje to vsechno co muze na dedicnosti? a jaky je pak logicky rozdil mezi tim mit dva base presentery? Tady jsou prece taky, jen jsou zkryty (resp jeden z nich je puvodni z nette).


Navic pres ty dva presentery (Base a BaseSecured) to ma i dalsi vyhodu v tom, ze pro prihlaseny uzivatele obvykle potrebujes i neco vic nez jen to overeni/presmerovani. Napr. ten handleLogout() jak sem zminoval vyse je presny kandidat, ktery ma v BaseSecured svoje misto (naopak v Base nema co delat). Nebo nejaka komponenta ktera se zobrazuje pouze prihlasenymu uzivateli, nejaky specialni polozky menu, … A tady ta vyhoda uz je zrejma…

llsm
Člen | 121
+
0
-

Aurielle napsal(a):

Kdyby se někomu zdála struktura BasePresenter → SecuredPresenter → FooPresenter moc komplexní, dá se to vyřešit i tak, že v SignPresenteru přetížíte metodu startup() tak, že nebude volat startup() z vašeho BasePresenteru, ale přímo z Nette\Application\UI\Presenter

Páni, na jednu stranu mi to prijde hrozne pekny, na druhou stranu to prekonava nejednu uroven WTF. Rozhodne kdybych prisel k cizimu kodu, ktery by to takto mel, tak bych se asi dlouho chvili nechytal.

hAssassin napsal(a):

Navic pres ty dva presentery (Base a BaseSecured) to ma i dalsi vyhodu v tom, ze pro prihlaseny uzivatele obvykle potrebujes i neco vic nez jen to overeni/presmerovani. Napr. ten handleLogout() jak sem zminoval vyse je presny kandidat, ktery ma v BaseSecured svoje misto (naopak v Base nema co delat). Nebo nejaka komponenta ktera se zobrazuje pouze prihlasenymu uzivateli, nejaky specialni polozky menu, … A tady ta vyhoda uz je zrejma…

Tim logoutem jsi me asi presvedcil, ze to je i praktictejsi nez oskliva podminka. Diky

duke
Člen | 650
+
0
-

Ještě existuje jedna možnost a sice v BasePresenteru vyčlenit kontrolu a případnou redirekci do zvláštní metody (volané z BasePresenter::startup) a tuto metodu pak ve všech Presenterech, kde nechci tuto kontrolu, nebo ji chci nějak omezit, překrýt. Tj.

class BasePresenter extends Nette\Application\UI\Presenter
{
	public function startup()
	{
		parent::startup();
		$this->ensureAccessible();
	}

	protected function ensureAccessible()
	{
		if (!$this->getUser()->isLoggedIn()) $this->redirect('Sign:in');
	}
}

… a v SignPresenteru mít:

	protected function ensureAccessible()
	{
		if ($this->action !== 'in') parent::ensureAccessible();
	}
Aurielle
Člen | 1281
+
0
-

@hAssassin: nikdo netvrdí, že je to vhodné řešení, jen mi přišlo vhodné ho v tomto tématu uvést, když jsem na začátku viděl ty podmínky kontrolující presenter a akci.

Jan Tvrdík
Nette guru | 2595
+
0
-

llsm wrote:

Musis kontrolovat tedy i jestli jsi na prihlasovaci strance a pokud ano, tak aby se redirect neprovedl. Neco jako:

<?php
 if ((!$this->user->isLoggedIn()) && ($this->reflection->name != 'SignPresenter' && $this->getAction() != 'in')) $this->redirect('Sign:in');
?>

Jen doplním, že místo $this->reflection->name je výrazně lepší zavolat $this->getName() což vrací název aktuálního presenteru.