Uprava udajov uzivatela v metode authenticate
- sabrx
- Člen | 47
Zdravim, mam takyto problem s metodou authenticate v modeli Authenticator na prihlasovanie.
Mam tabulku st_user obsahujucu stlpec tz_city_id, co je cudzi kluc do tabulky tz_city s nazvami miest. V aplikacii potrebujem pracovat s nazvom mesta, a tak pri prihlasovani uzivatela vykonam v metode authenticate:
<?php
if ($row)
$row->tz_city_id = $row->tz_city->city_name;
?>
cim prepisem id mesta, ktore sa vytiahlo zo zaznamu uzivatela, jeho nazvom z tabulky miest.
A teraz k problemu. To prepisovanie funguje chvilu (zopar prihlaseni), a potom to zrazu pri dalsom prihlaseni prestane fungovat, udaj sa vobec neprepise, ako by tam ten riadok kodu ani nebol. Dakujem za pomoc. Mam Nette 2.0.5 na localhost, PHP 5.4.6.
- sabrx
- Člen | 47
Models\Authenticator.php:
<?php
/**
* Performs an authentication
* @param array
* @return Nette\Security\Identity
* @throws Nette\Security\AuthenticationException
*/
public function authenticate(array $credentials)
{
list($username, $password) = $credentials;
$row = $this->users->findByName($username);
if ($row)
$row->tz_city_id = $row->tz_city->city_code;
if (!$row) {
throw new NS\AuthenticationException("User '$username' not found.", self::IDENTITY_NOT_FOUND);
}
if ($row->pass_hash !== self::calculateHash($password, $row->pass_hash)) {
throw new NS\AuthenticationException("Invalid password.", self::INVALID_CREDENTIAL);
}
if (!$row->activated) {
throw new NS\AuthenticationException("Account not yet activated.", self::NOT_APPROVED);
}
unset($row->pass_hash);
return new NS\Identity($row->id, NULL, $row->toArray());
}
?>
V sablone si zavolam:
<?php
{$user->getIdentity()->tz_city_id}
?>
- sabrx
- Člen | 47
Az po presmerovani, kedze tz_city_id volam az v sablone. Volam tam tento kod:
<?php
date_default_timezone_set($user->getIdentity()->tz_city_id)
?>
Ak sa to nastavi, je tam napriklad „Europe\Prague“, takze OK, inak to vyhodi chybu, co je jasne, lebo ked sa to neprepise v authenticate, je tam ID.
- elendir
- Člen | 31
Identita se instancializuje dvěma způsoby – buď uvnitř login() anebo ze $_SESSION (pro dříve zalogovaného uživatele). Na tvém místě bych nejdřív zkusil zjistit, kde se ta identita instancializuje špatně – jestli je to hned v login():
$user->login(...);
Nette\Diagnostics\Debugger::dump($user->getIdentity());
anebo až po přesměrování, poté co je zrekonstruována ze $_SESSION.
Také bych zkusil to pole hodnot do identity neposílat přes
$row = $this->users->findByName($username);
$row->tz_city_id = $row->tz_city->city_code;
return new NS\Identity($row->id, NULL, $row->toArray());
protože kdoví jaká magie se uvnitř těchto tříd skrývá. Nevím, nikdy jsem s nimi nepracoval, ale abych vyloučil ukládání jakýchkoliv neserializovatelných objektů a referencí do identity, změnil bych to alespoň dočasně na:
$row = $this->users->findByName($username);
$data = array();
$data['tz_city_id'] = $row->tz_city->city_code;
return new NS\Identity($row->id, NULL, $data);
Je samozřejmě možné že to ani potom nebude fungovat, ale minimálně se tím razantně zúží prostor kde hledat problém.
Editoval elendir (29. 10. 2012 21:10)
- sabrx
- Člen | 47
Vdaka za dobre rady, zatial to funguje, takze budem musiet pockat, az sa to zase pokazi.
Co sa tyka metody findByName, tam nie je ziadna magia, je to v modeli UserTable, a vracia zaznam vo forme pola:
<?php
public function findByName($username) {
return $this->findBy(array('username' => $username))->fetch();
}
?>
Metoda findBy vracia ActiveRow. To mi vlastne doslo az teraz, nemohlo by to byt tym, ze sa snazim priamo v objekte ActiveRow nastavit hodnotu atributu?
- elendir
- Člen | 31
nemohlo by to byt tym, ze sa snazim priamo v objekte ActiveRow nastavit hodnotu atributu?
Vyloučit to nelze, tu třídu neznám, ale to by ti to nefungovalo nikdy, ne? Ty ale píšeš že to nefunguje „jak kdy“. Proto úplně první věc co je imho potřeba zjistit je jestli se správně uložila ta identita. Píšeš že už ti to funguje, no kdyby přestalo, přidej si hned za
$user->login(...);
(což předpokládám máš v Sign:in) tyto řádky:
Nette\Diagnostics\Debugger::$maxDepth = 10;
Nette\Diagnostics\Debugger::dump($user->getIdentity());
Nette\Diagnostics\Debugger::dump($_SESSION);
aby se zjistilo jestli se správně vytvořila identita a jestli se zároveň správně uložila do session. Pak sem postni oba ty dumpy. Dokud neuděláš tohle tak těžko vyvozovat nějaké závěry. Taky se zkus mrknout na vlákno přepsání identity, jestli by s tím náhodou tvůj problém nemohl souviset.
- sabrx
- Člen | 47
Takže práve som náhodou zistil, kedy to prestáva fungovať. Keď sa pokúsim prihlásiť s nesprávnym heslom, a následne správnym, tz_city_id vo vraátenej identite je nezmenené, teda zmena
<?php
if ($row)
$row->tz_city_id = $row->tz_city->city_code;
?>
vykonaná v metóde authenticate (pozri môj prispévok vyššie) sa neprejaví. Po premazaní cache sa zmena už prejaví, a identita obsahuje upravenú premennú.
Moja domnienka je, ze sa pri prvom pokuse o prihlásenie uloží pôvodný záznam z tabuľky do cache, a pri druhom pokuse sa odtiaľto vytiahne, lebo Nette predpokladá, ze v authenticate nebudem nič modifikovať, takže na čo zasa zaťažovať databázu rovnakým dotazom. Je na tom niečo? Ak áno, dá sa tomuto správaniu nejako zabrániť?
- sabrx
- Člen | 47
elendir napsal(a):
nemohlo by to byt tym, ze sa snazim priamo v objekte ActiveRow nastavit hodnotu atributu?
Vyloučit to nelze, tu třídu neznám, ale to by ti to nefungovalo nikdy, ne? Ty ale píšeš že to nefunguje „jak kdy“. Proto úplně první věc co je imho potřeba zjistit je jestli se správně uložila ta identita. Píšeš že už ti to funguje, no kdyby přestalo, přidej si hned za
$user->login(...);
(což předpokládám máš v Sign:in) tyto řádky:
Nette\Diagnostics\Debugger::$maxDepth = 10; Nette\Diagnostics\Debugger::dump($user->getIdentity()); Nette\Diagnostics\Debugger::dump($_SESSION);
aby se zjistilo jestli se správně vytvořila identita a jestli se zároveň správně uložila do session. Pak sem postni oba ty dumpy. Dokud neuděláš tohle tak těžko vyvozovat nějaké závěry. Taky se zkus mrknout na vlákno přepsání identity, jestli by s tím náhodou tvůj problém nemohl souviset.
Po pridani prikazu
<?php
Nette\Diagnostics\Debugger::dump($_SESSION);
?>
sa mi vratila chyba Nette\InvalidStateException, Cannot set HTTP code after HTTP headers have been sent.
- sabrx
- Člen | 47
Zdravím, takže asi som ten problém už vyriešil. Metódu authenticate som upravil tak, že riadok databázy $row som hneď previedol na pole, a až v tomto poli som si upravil príslušnú položku. Do identity som samozrejme pridal toto pole. Určite tu ide o to, že Nette vždy nazrie do cache, či tam náhodou nie je rovnaký záznam. Aj keby áno, stále to nevysvetľuje, prečo sa kód
<?php
if ($row)
$row->tz_city_id = $row->tz_city->city_code;
?>
vykoná len vtedy, keď sa do procesu nezapája cache.
Editoval sabrx (9. 11. 2012 12:12)