Nette — aktualizace identity
Něco málo o IdentityHandler, protože oficiální dokumentace mi v tomto případě přijde poněkud nepřesná, či dokonce zavádějící.
O identitě se píše zde, což je popsáno docela dobře. Hned pod tím začíná část o uložišti uživatele a tady už si dovolím tvrdit, že dokumentace nepatří mezi nepřesnější. Že je uložiště buďto na bázi session nebo cookies pochopí každý, jaké a kdy použít už nikoli.
Hned první příklad ukazuje, jak změnit identitu při výchozí nastavení uložiště session:
final class Authenticator implements
Nette\Security\Authenticator, Nette\Security\IdentityHandler {
public function sleepIdentity(IIdentity $identity): IIdentity {
return $identity;
}public function wakeupIdentity(IIdentity $identity): ?IIdentity {
$userId = $identity->getId();
$identity->setRoles($this->facade->getUserRoles($userId));
return $identity;
}
}
Potud vše OK, problémem je, že to prostě nefunguje. Ukládá se jen uživatelovo ID a podle něj je třeba vše zase obnovit. A když jsem se tento kód (samozřejmě mírně upraven pro mé konkrétní použití) pokusil zprovoznit, identita nefungovala a Nette pořád hlásilo nějaké chyby.
Inu začetl jsem se dál a zjistil, že onen IdentityHandler na stránkách Nette funguje pod cookies. Dobře, nastavil jsem tedy cookieStorage v configu:
security:
authentication:
storage: cookiePo této chvíli se sice kód rozjel, ale chyby nezmizely. Nyní totiž Nette hlásilo, že ukládané ID je malé. On je totiž problém že obyčejné:
return $identity;uloží do uložiště pouze ID, což zpravidla nebývá moc velké číslo. CookieStorage ovšem očekává řetězec, alespoň o 13 znacích. Jenže o tom se v dokumentaci nepíše, jen že řetězec v DB (authToken) má mít minimálně 13 znaků.
Get anonymní Panda’s stories in your inbox
Join Medium for free to get updates from this writer.
No nevadí, naštěstí je tam (už) i druhý příklad. Přísahal bych, že když jsem to řešil u sebe, ta dokumentace byla v jiném formátu, proto jsem měl ty výhrady. Nyní se zdá, že už je to alespoň trošku opraveno. Každopádně, výše uvedený kód je třeba trochu upravit:
public function sleepIdentity(IIdentity $identity): IIdentity {
return new SimpleIdentity($identity->authToken);
}public function wakeupIdentity(IIdentity $identity): ?IIdentity {
$row = $this->database->table('users')
->where('authToken', $identity->getId())
->fetch();$roles = []; // to pole je třeba nějak naplnitreturn new SimpleIdentity(
$row->id,
$roles,
['name' => $row->username, 'authToken' => $row->authToken]
);
}
Po této úpravě už všechno funguje. Základem je, že se při uspání nepředává ID, ale authToken (který má minimálně těch 13 znaků a je unikátní pro každého uživatele). Při obnovení se obnoví jen tento token, který je k dispozici pod metodou getId(), což nepovažuji za úplně optimální. Pro někoho to může být zavádějící.
Každopádně získáte zase uložený token, podle něj získáte data z DB a můžete znovu načíst i role. Takže se velmi snadno dá pracovat s tím, že se změny projeví i u přihlášených uživatelů a to okamžitě, bez nutnosti se odhlásit a znovu přihlásit.
Nutno říct, že když jsem si článek chystal, dokumentace byla v podstatně horším stavu, než je nyní. Asi těch lidí, co měli problém, bylo více, takže vývojáří dokumentaci změnili. Za to jsem jedině rád, přesto svůj článek vydávám.






