Autentizace v Modularni aplikaci, jak na to? (PHP 5.2.9)
- Endrju
- Člen | 147
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)
- Endrju
- Člen | 147
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)
- BigCharlie
- Člen | 283
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
jasir napsal(a):
- zkus smazat obsah adresáře app/temp
- v metodě startup volej
parent::startup()
na začátku metody.- v metodě
beforeRender
volejparent::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
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
Pravděpodobně tam setuješ proměnnou třídy a nebo templaty a když to zakomentuješ, tak iterace vyhodí výjimku.
- jasir
- Člen | 746
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
volejparent::beforeRender()
(vyhneš se problémům pokud bys tuto metodu měnil v nějakém BasePresenteruUdelal 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 nekdybeforeRender()
.
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 postartup()
. Pritom metodastartup()
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
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
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
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 :))