Update SimpleIdentity přihlášeného uživatele bez reinit session

fulda
Člen | 3
+
0
-

Zdravím,
řeším pro zkušené možná triviální problém, ale nevím jak z něj. Mám presenter pro změnu osobních údajů (jméno, atp.). Změny prováním pomocí ajax+snippetů. Co položka to snippet a vlastní formulářík na stránce na změnu hodnoty. Problém je, že některé položky např. jméno bych potřeboval po změně a uložení do DB logicky updatovat i v aktuální identitě.
Šel jsem na to naivně a po změně při zpracování formu jsem vytvořil novou SimpleIdentity a zavolal $user->login() s novou identitou. To sice aktualizuje identitu, ale přestanou pak fungovat snippety. Metodou pokus omyl jsem došel k závěru, že login nastaví novou session a tím to celé asi odejde, protože snippety přijímají jiná resp. žádná data v payload…

Lze nějak updatovat identitu se zachováním session resp. v kombinaci se snippety? Jak se toto řeší? Nechat uživatele odhlásit/přihlásit pro aplikaci změn mi nepřijde úplně dobré řešení.

Ještě mě napadlo mít v identitě jen ID uživatele a pak všechno ostatní okolo uživatele vždy vytahat z DB v případě potřeby. To ale to taky není úplně optimální, že – když se data identity téměř nikdy po přihlášení nemění.

Btw. Jak v knihovně naja (event ‚complete‘) zjistím, který snippet byl aktualizován?

Kamil Valenta
Člen | 833
+
0
-

Sessid se mění, login() nejprve zavolá logout(true).

Nestačilo by si jen přepsat wakeupIdentity()?

Editoval Kamil Valenta (4. 3. 15:31)

fulda
Člen | 3
+
0
-

wakeupIdentity() jsem prozkoumal i vyzkoušel, ale není to úplně ono. Jednak asi nechci, aby to neustále při každém requestu updatovalo identitu z DB (proč, když toto je řešení velmi okrajové situace a aplikuje se pouze v momentě, kdy si uživatel bude měnit osobní údaje). A pak to samozřejmě nefunguje pro aktuální request tak, aby aktualizovaný snippet měl k dispozici aktualizované hodnoty v $user->identity->data[]. A aby se vyvolal wakeup musí dojít k redirect (předpokládám), čili dokud budu na stránce se snippety, identita bude stále původní, i když už jsem si změnil jméno, …

Nette zjevně chrání session a při jakékoli změně identity i např. při volání $this->user->getStorage()->saveAuthentication($updatedIdentity); dojde je změně id session. Z bezpečnostního hlediska asi dobrá vlastnost, takže bych se jí nerad zbavil nějakým vypnutím v config (pokud to vůbec lze).

Napadá mě po různých pokusech jen řešení si uložit do session nějaký příznak „updateIdentityOnWakeup = true“ a ve fci wakeupIdentity() provest aktualizaci z DB pouze v tomto případě. Změnu pro aktuální request řešit hackem:

// Ruční přepis identity pro aktuální request (paměť)
$reflection = new \ReflectionProperty($this->user, 'identity');
$reflection->setAccessible(true);
$reflection->setValue($this->user, $updatedIdentity);

Ale je to asi trochu fuj řešení.

Kamil Valenta
Člen | 833
+
0
-

fulda napsal(a):

Jednak asi nechci, aby to neustále při každém requestu updatovalo identitu z DB

To přece nemusí, jednotlivé updaty z formuláře si můžeš uložit do sessiony. WakeupIdentity se pak do sessiony jen podívá, zda tam nejsou „odloženy“ nějaké aktualizace od posledního login().

fulda
Člen | 3
+
0
-

Jasně, to je samozřejmě pravda.

Zdá se, že vykrystalizovalo životaschopné řešení v podobě uložení změněné části identity do session a k tomu příznak, že nastala změna identity od posledního login. Pak, při každém wakeupIdentity, je zkontrolován příznak a pokud je změna, se upraví identita daty uloženými v session. Zdá se, že funkční.

Díky za nasměrování.

	public function wakeupIdentity(IIdentity $identity): ?IIdentity
	{
		$session = $this->session->getSection('nette-user');
		// Ověříme, zda byla identita upravena (v uživatelském nastavení)
		if ($session->get('updatedIdentity')) {
			// Získáme updatovana data identity
			$updatedData = $session->get('updatedData') ?? [];
			// Vytvoříme novou identitu s updatovanymi daty
			$updatedIdentity = new Nette\Security\SimpleIdentity(
				$identity->getId(),
				$identity->getRoles(),
				array_merge((array) $identity->getData(), $updatedData)
			);
			return $updatedIdentity; // Vracíme aktualizovanou identitu
		}
		return $identity; // Beze změny identita stejná jako po přihlášení
	}

Jiné řešení, aniž by došlo ke změněně session po updatu identity a tímpádem znefunkčnění snippetů, se mi nepodařilo najít.