Autentizace v Modularni aplikaci, jak na to? (PHP 5.2.9)

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

Zdravim, potreboval bych poradit jak vytvorit autentikaci v modularni aplikaci (pouzivam PHP 5.2.9).

Struktura:

Apliakce/
+--app/
|  +--AdminModule/
|  |  +--presenters/
|  |  |  +--AuthPresenter.php
|  |  |  +--BasePresenter.php
|  |  |  +--HomepagePresenter.php
|  |  +--templates/
|  |  + ...
|  +--FrontModule/
|  |  +--presenters/
|  |  +--templates/
|  |  + ...
|  +--models/
|  +--presenters/
|  |  +--BasePresenter.php
|  + ...
+--document_root/
|  + ...
+--libs/
|  + ...
+ ...

Pozadavek na login chci vytvorit pro vsechny stranky v Admin modulu. Tedy kdyz uzivatel podstraci jakoukoli URL na stranku v administraci a nebyl prihlasen, tak bude presmerovan na prihlaseni.

Snazil jsem se upravit priklad examples\CD-collection z distribude, ale zda se, ze nevim jak to spravne upravit pro tuto modularni aplikaci. Byl bych moc vdecny za vasi pomoc.


Routy mam nastaveny takto:

<?php
// mod_rewrite detection
if (function_exists('apache_get_modules') && in_array('mod_rewrite', apache_get_modules())) {
  $router[] = new Route('admin/index.php', array(
		'module' => 'Admin',
		'presenter' => 'Default',
	), Route::ONE_WAY);

	$router[] = new Route('admin/<presenter>/<action>/<id>', array(
		'module' => 'Admin',
		'presenter' => 'Default',
		'action' => 'default',
		'id' => NULL
	));

	$router[] = new Route('index.php', array(
		'module' => 'Front',
		'presenter' => 'HomePage',
	), Route::ONE_WAY);

	$router[] = new Route('<presenter>/<action>/<id>', array(
	  'module' => 'Front',
		'presenter' => 'HomePage',
		'action' => 'default',
		'id' => NULL,
	));

} else {
	$router[] = new SimpleRouter('Front:HomePage:default');
}
?>

Admin a Front BasePresenter dedi z globalniho BasePresenteru.

Globalni BasePresenter:

<?php
abstract class BasePresenter extends Presenter
{
	public $oldLayoutMode = FALSE;
	public $oldModuleMode = FALSE;
}
?>

Admin BasePresenter:

<?php
class Admin_BasePresenter extends BasePresenter
{
	protected function beforeRender()
	{
		$user = Environment::getUser();
		$this->template->user = $user->isAuthenticated() ? $user->getIdentity() : NULL;
	}
}
?>

Kazdy dalsi presenter v Admin modulu dedi z Admin_BasePresenter. Tedy kod, ktery by mel overovat, zda je uzivatel prihlasen, bych ocekaval prave tam.

V prikladu CD-collection v presenteru Dashboard pak byla funkce startup(). Tu jsem tedy zkopiroval do presenteru Homepage (v Admin modulu), ktery se nacita (take) jako prvni pri spusteni Admin modulu (viz. nastaveni rout).

<?php
class Admin_HomepagePresenter extends Admin_BasePresenter
{
	protected function startup()
	{
		// user authentication
		$user = Environment::getUser();
		if (!$user->isAuthenticated()) {
			if ($user->getSignOutReason() === User::INACTIVITY) {
				$this->flashMessage('You have been logged out due to inactivity. Please login again.');
			}
			$backlink = $this->getApplication()->storeRequest();
			$this->redirect('Admin:Auth:login', array('backlink' => $backlink));
		}

		parent::startup();
	}
}
?>

Problem:

Krome toho, ze nevim, zda to mam vubec dobre :) mi ladenka pise error (prelozit si chybu umim, ale vazne nevim co s tim..):

Compile Error
Cannot redeclare class Admin_HomepagePresenter

File: D:\webserver\SK_Celadna\app\AdminModule\presenters\HomepagePresenter.php Line: 21

<?php
Line 14:                $backlink = $this->getApplication()->storeRequest();
Line 15:                $this->redirect('Admin:Auth:login', array('backlink' => $backlink));
Line 16:            }
Line 17:
Line 18:            parent::startup();
Line 19:        }
Line 20:
Line 21:    }
}Line 22:
?>
Call stack ▼
   1. <PHP inner-code> Debug:: _shutdownHandler ()

Napsal jsem zde snad vse potrebne a potreboval bych to rozchodit. Byl bych nesmirne stastny, kdyby jste si nekdo dali ten cas a napsali mi v cem mam chyby a napsali mi, jak by to melo byt…

Predem moc moc dekuji :)!

Editoval Endrju (23. 2. 2010 9:38)

toka
Člen | 253
+
0
-

Podle mne máš v projektu dvě stejné třídy Admin_HomepagePresenter.

Endrju
Člen | 147
+
0
-

To opravdu nemam. Aplikace prestala fungovat, kdyz jsem pridal funkci beforeRender() do tridy Admin_BasePresenter a funkci startup() do tridy Admin_HomepagePresenter.

V podstate staci aby tam byla jen jedna z techto dvou funkci, aby to vyhazovalo vyse zminovanou chybu..

Davidku, svolame te shury :). Prosim poradte nekdo..

Editoval Endrju (23. 2. 2010 10:54)

jasir
Člen | 746
+
0
-
  • zkus smazat obsah adresáře app/temp
  • v metodě startup volej parent::startup() na začátku metody.
  • v metodě beforeRender volej parent::beforeRender() (vyhneš se problémům pokud bys tuto metodu měnil v nějakém BasePresenteru

Editoval jasir (23. 2. 2010 11:10)

BigCharlie
Člen | 283
+
0
-

Nejsem si jist, ale kdyby byly dva Admin_BasePresentery, výjimku by vyhodil už RobotLoader, tohle vypadá na pozdější chybu. Protože předpokládám, že app\temp jsi smazal, je třeba hledat, co přesně tu chybu vyvolá.

Co když tam necháš ty metody prázdné (tj. zakomentuješ kód) – resp. ve startupu musí zůstat parent::startup();? Je potřeba najít minimální kód, na kterém to padá.

Endrju
Člen | 147
+
0
-

jasir napsal(a):

  • zkus smazat obsah adresáře app/temp
  • v metodě startup volej parent::startup() na začátku metody.
  • v metodě beforeRender volej parent::beforeRender() (vyhneš se problémům pokud bys tuto metodu měnil v nějakém BasePresenteru

Udelal jsem presne to, co jsi napsal a funguje to (tedy zobrazi se mi stranka s loginem a podari se uvereni uzivatele v DB + presmerovani na Homepage v Admin modulu). Dekuji za to.

Vubec ale nerozumim tem zmenam ktere jsem provedl. Take nevim proc se jednotlive metody volaji tak jak se volaji a byl bych happy, kdyby jste mi to vysvetlili :). Prosim :).

Z toho co jsem se doposud docetl vim, ze zivotni cyklus presenteru je takovy, ze prvni se vykonava startup() a az pak nekdy beforeRender().

Takze kdyz spustim Admin_HomepagePresenter, kteri dedi z Admin_BasePresenter, tak by se melo prvni vykonavat to co je v Admin_BasePresenter, prozote je z nej dedeno ne?

Mam v tim nesrovnalosi, protoze v Admin_BasePresenter je metoda beforeRender(), ktera se ale (podle zivotniho cyklu) vykonava az po startup(). Pritom metoda startup() je ale volana az v potomkovi metody Admin_BasePresenter tedy v Admin_HomepagePresenter.

Z toho vyplyva ze to bud nechapu a nebo:

je prubeh takovy, ze kdyz volam Admin_HomepagePresenter, ktery dedi z Admin_BasePresenter, tak se nejprve vykona cely zivotni cyklus presenteru Admin_BasePresenter a pak teprve cely zivotni cylus presenteru Admin_HomepagePresenter. Jedine pak by to davalo nejaky smysl.

Pak to ale popira to co jsem si myslel, a to je: ze se vykonava v podstate jediny Presenter, ktery diky dedeni ziskava urcite vlastnosti. Tedy pokud bych chtel volat beforeRender() a take startup(), tak to musim provest ve spravnem poradi a tudiz bych v dedene metode nemohl volat startup() a v rodicovske metode beforeRender(). Takto to je tedka…

Jsem z toho pomateny :/

Endrju
Člen | 147
+
0
-

BigCharlie napsal(a):

Nejsem si jist, ale kdyby byly dva Admin_BasePresentery, výjimku by vyhodil už RobotLoader, tohle vypadá na pozdější chybu. Protože předpokládám, že app\temp jsi smazal, je třeba hledat, co přesně tu chybu vyvolá.

Co když tam necháš ty metody prázdné (tj. zakomentuješ kód) – resp. ve startupu musí zůstat parent::startup();? Je potřeba najít minimální kód, na kterém to padá.

no a co se tyka tohoto:

kdyz zakomentuju startup() i beforeRender(), tak to funguje.

Kdyz odpomentuju beforeRender(), ale zakomentuju vnitrek teto metody, tak to vyhodi tuto chybu:

InvalidArgumentException
Invalid argument passed to foreach resp. SmartCachingIterator; array or Iterator expected, NULL given.

Kdyz zakomentuju celou metodu beforeRender(), ale necham odkomentovanou metodu startup() (tedy jakoby metoda beforeRender() vubec nebyla), tak to vynguje uplne stejne jako bych tam tu metodu mel. Cimz vznika moje dalsi otazka – jaky tam ta metoda ma vyznam?

Mikulas Dite
Člen | 756
+
0
-

Pravděpodobně tam setuješ proměnnou třídy a nebo templaty a když to zakomentuješ, tak iterace vyhodí výjimku.

jasir
Člen | 746
+
0
-

Endrju napsal(a):

jasir napsal(a):

  • zkus smazat obsah adresáře app/temp
  • v metodě startup volej parent::startup() na začátku metody.
  • v metodě beforeRender volej parent::beforeRender() (vyhneš se problémům pokud bys tuto metodu měnil v nějakém BasePresenteru

Udelal jsem presne to, co jsi napsal a funguje to (tedy zobrazi se mi stranka s loginem a podari se uvereni uzivatele v DB + presmerovani na Homepage v Admin modulu). Dekuji za to.

Vubec ale nerozumim tem zmenam ktere jsem provedl. Take nevim proc se jednotlive metody volaji tak jak se volaji a byl bych happy, kdyby jste mi to vysvetlili :). Prosim :).

Když se objeví chyba typu „podruhé deklaruješ třídu xy“, jsou dvě možnosti -
buď je tam opravdu dvakrát a nebo jsi přesouval třídy mezi soubory. Pak může být stará cache Robotloaderu a výsledkem je tato chyba.

Volání startup přesunout proto, že když se na metodu jak jsi jí měl podíváš tak pokud se ta podmínka vyhodnotí a provede se redirect, parent::startup() se pak nezavolá nikdy. Volat ho jako první ve svém startup je tedy nejbezpečnější.

Doplnění volání parent::beforeRender() není nyní nutné, protože v BasePresenteru či dalších předcích je tato metoda prázdná. Ale pokud bys jednou do té metody v BasePresenteru něco přidal (manipulaci s template, …cokoliv), už by se nevolala, protože bys jí svou beforeRender() překryl kompletně.

Z toho co jsem se doposud docetl vim, ze zivotni cyklus presenteru je takovy, ze prvni se vykonava startup() a az pak nekdy beforeRender().

tohle si bezpodmínečně prostuduj životní cyklus

Takze kdyz spustim Admin_HomepagePresenter, kteri dedi z Admin_BasePresenter, tak by se melo prvni vykonavat to co je v Admin_BasePresenter, prozote je z nej dedeno ne?

:-) Ano, ty přeci vytvoříš novou třídu Admin_HomepagePresenter,
která je shodná jako Admin_BasePresenter, kromě těch metod, které jsi přepsal. To je základ dědičnosti.

Mam v tim nesrovnalosi, protoze v Admin_BasePresenter je metoda beforeRender(), ktera se ale (podle zivotniho cyklu) vykonava az po startup(). Pritom metoda startup() je ale volana az v potomkovi metody Admin_BasePresenter tedy v Admin_HomepagePresenter.

Z toho vyplyva ze to bud nechapu a nebo:

je prubeh takovy, ze kdyz volam Admin_HomepagePresenter, ktery dedi z Admin_BasePresenter, tak se nejprve vykona cely zivotni cyklus presenteru Admin_BasePresenter a pak teprve cely zivotni cylus presenteru Admin_HomepagePresenter. Jedine pak by to davalo nejaky smysl.

Tak to opravdu není. Existuje jen jedna instance presenteru, konkrétně instance Admin_HomepagePresenteru. Na ní se pak volají metody životního cyklu (startup, action<action>, beforeRender, render<view> ).
Pokud je metoda přepsaná v Admin_HomepagePresenteru, volá se tato metoda, jinak se volají metody v BasePresenteru či Admin_BasePresenteru.

Jsem z toho pomateny :/

Ano, ale to se podá.

Editoval jasir (23. 2. 2010 13:15)

Endrju
Člen | 147
+
0
-

Dekuji jasir! Uz se netopim, ale docela obstojne slapu vodu hehe :).

Mel bych jeste jednu otazku (prosbu):

Kdyz totiz, zadam nejakou jinou adresu (presenter) z Admin modulu, tak se neprovadi ona metoda startup() a tim padem to obejde prihlaseni. Zaroven se mi ale nepozdava to, ze bych tu samou identickou metodu startup() musel mit v kazdem dedenem presenteru tridy Admin_BasePresenter (jinymi slovy na kazde strance v Admin modulu).
Puvodne jsem ten startup() chtel dat taky rovnou do Admin_BasePresenter (prislo mi to logicke – chci to overovat pro kazdou stranku), ale pri spusteni se to akorat zacyklilo.

Poradis mi prosim jak tohle udelat?

jasir
Člen | 746
+
0
-

Máš to přeci takto: v presenterech dědících od Admin_BasePresenter (kde je tvá startup) musí mít zalogovaného uživatele, jinak se přesměruje na login.
Z toho vyplývá, že presenter obsluhující login tam tuto kontrolu mít nesmí, jinak se zacyklí.

Dá se toho docílit například strukturou presenterů:

Admin_BasePresenter
  |-Admin_LoginPresenter
|-SecuredAdmin_BasePresenter (obsahuje startup, přesměrování)
  |-UserPresenter
  |-RedakcePresenter

Všechny presentery dostupné pouze po zalogování budou dědit od SecuredAdmin_BasePresenter.

Podívej se na strukturu presenterů v CD-Collection.

Presenter pro login dědí rovnou od Admin_BasePresenter.

Endrju
Člen | 147
+
0
-

Jo, to me nenapadlo mit talsi presender – Admin_SecuredBasePresenter (ten snad nemusi byt doslove tak jak pises).

V CD-Collection dedi rovnou z BasePresenter, ale tam taky uz zadny jiny presenter (stranka neni).

Kontrola loginu je v Dashboard coz je jedina stranka krome Auth presenteru, takze tam nemusi resit to, aby byla provadena kontrola na vsech dalsich stranakch, ktere maji byt zabezpecene… S tim Secured presenterem by to melo jit tak jak bych si predstavoval (pokud to neni teda moc prepresenterovane reseni :))