User se odhlašuje i když by neměl

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

Aneb jak někdo pozná, že opět vyvíjím nějaký web – stoupne frekvence mého přispívání na fórum :o)

Dělám přihlašování uživatelů. Navěsil jsem si na onAuthenticated a onSignedOut události, které mi u daného usera nastavují online flag na 1/0 (abych mohl vypisovat uživatele, kteří jsou právě online apod.). Pochvaloval jsem si, že Nette dokáže ten callback zavolat i v případě, že nastane odhlášení kvůli zavření browseru. Geniální :)

Jenže to z nějakého neznámého důvodu přestalo fungovat – ta metoda se nezavolá (pokud se přihlásím, zavřu browser a otevřu ho, tak flag v databázi je stále na 1, ale já jsem odhlášený) a dokonce mě to odhlašuje i tehdy, kdyby nemělo. Zkouším totiž kromě mého typického nastavení třeba i něco takového:

$user->setExpiration('+ 2 days');

Což by podle dokumentace mělo znamenat, že maximální doba inaktivity před odhlášením je 2 dny, nehledě na zavření browseru. Jenže mě to po zavření/otevření odhlásí (koukal jsem na tu Nette cookie a má fakt platnost relace do zavření browseru) a navíc se nezavolá ta událost.

Nějaké tipy, kde bych měl hledat příčinu nesprávného chování, případně které zdrojáky bych sem měl postnout? Díky moc.

Editoval LastHunter (24. 6. 2009 10:56)

R2D2
Člen | 22
+
0
-

a nemáš nastavenou menší expiraci session? (do zavření)

někde (v bootstrapu?) bys měl mít cosi jako

<?php
$session = Environment::getSession();
$session->setExpiration($expiration);
$session->start();
?>
Ondřej Mirtes
Člen | 1536
+
0
-

R2D2 napsal(a):

a nemáš nastavenou menší expiraci session? (do zavření)

někde (v bootstrapu?) bys měl mít cosi jako

<?php
$session = Environment::getSession();
$session->setExpiration($expiration);
$session->start();
?>

Díky, už funguje jak má :) Co kdyby třída User vyhazovala výjimku, pokud není splněná tato podmínka? Chová se pak totiž dost nestandardně…

lactarius
Člen | 47
+
0
-

Ondřej Mirtes napsal(a):
Dělám přihlašování uživatelů. Navěsil jsem si na onAuthenticated a onSignedOut události, které mi u daného usera nastavují online flag na 1/0 (abych mohl vypisovat uživatele, kteří jsou právě online apod.). Pochvaloval jsem si, že Nette dokáže ten callback zavolat i v případě, že nastane odhlášení kvůli zavření browseru. Geniální :)

Ahoj,

s online flagem v databázi je to dobrý nápad, akorát nevím, jak s událostmi onAuthenticated / onSignedOut – zkoušel jsem je nastavit v bootstrapu:

Environment::getUser()->onAuthenticated[] = 'UsersModel::userAuthenticated';
Environment::getUser()->onSignedOut[] = 'UsersModel::userSignedOut';

UsersModel:

public static function userAuthenticated()
{
	$name = Environment::getUser()->getIdentity()->username;
	dibi::query("UPDATE users SET online=TRUE WHERE username='$name'");
}

public static function userSignedOut()
{
	$name = Environment::getUser()->getIdentity()->username;
	dibi::query("UPDATE users SET online=FALSE WHERE username='$name'");
}

Takhle to nějak funguje – ale nejsem si jist, co právě v připadě ‚neregulérního‘ odhlášení – tj. vypnutí prohlížeče – pokud bude expirace nastavena třeba na + 14 days, tak bude ta informace dost nepravdivá…

Vyki
Člen | 388
+
0
-

Taky jsem se na něčem podobném nachytal, ale naštěstí jsem měl u sebe poznámky a zdrojáky z Davidovo přednášky, které mi to pomohly vyřešit. Ono to dává logiku, že žádná samostatná session proměnná nemůže mít dobu expirace nastavenou na delší dobu než je nastaveno obecně pro session (všechny session).

Editoval Vyki (26. 1. 2010 16:08)

lactarius
Člen | 47
+
0
-

Ještě k události onSignedOut – dnes jsem měl možnost to v klidu otestovat. Tato událost skutečně proběhne pouze v případě, že se uživatel ‚legálně‘ odhlásí.

Environment::getUser()->signOut();

Jinak se změna stavu uživatele projeví až při přihlášení jiného uživatele do stejného prostoru, něco podobného už se tu řešilo:
https://forum.nette.org/…thenticatory
Takže tudy cesta ke zjištění ‚fyzické přítomnosti‘ uživatele nevede…

Ondřej Mirtes
Člen | 1536
+
0
-

Jo, na to jsem už taky přišel. Navíc by to hlásilo jako online lidi třeba ty, kteří na webu vůbec nejsou, ale mají aktivní „stálé přihlášení“ třeba na 14 dní.

Jako možné řešení se nabízí zaznamenávat „last click“ u každého uživatele a vybírat pak jen ty řádky, kde "last_click > time() - 1800" (kliky za poslední půlhodinu).

Editoval Ondřej Mirtes (28. 1. 2010 18:01)

lactarius
Člen | 47
+
0
-

Takže místo online flagu u každého uživatele záznam času poslední akce – třeba odeslání formuláře. Plus sekvenční kontrola všech uživatelů – buď ručně, nebo v intervalu.
Asi nejsofistikovanější odpověď by přišla od někoho ze Spedie nebo CashSurfers – ale tam by zřejmě nebyli moc sdílní…

Ondřej Mirtes
Člen | 1536
+
0
-

Stačí dát volání toho updatu přihlášeného uživatele třeba do startupu BasePresenteru.

dibi::query('UPDATE [users] set [last_click]=%i', time(), ' WHERE [id]=%i', $this->getUser()->getIdentity()->getId());

A počet aktuálně online (aktivních uživatelů za poslední půlhodinu):

$onlineCount = dibi::fetch('SELECT count(*) FROM [users] WHERE [last_click]>%i', time() - 1800);

Žádný cron nebo něco takového zde není potřeba. Je to jen základní princip, třeba někoho napadnou „zlepšováky“.

Editoval Ondřej Mirtes (28. 1. 2010 18:02)

lactarius
Člen | 47
+
0
-

Jo – tak takhle to fakt funguje. Testoval jsem to na chatu, takže jsem update nedal do BasePresenteru, ale do handle, který se stará o zpracování zpráv – přičemž se stav kontroluje ve chvíli, kdy odněkud dorazí zpráva – sice by to šlo kontrolovat pokaždé, kdy si klient ‚sáhne‘ na server pro případné nové zprávy – ale naco, takhle to bohatě stačí.
handleExchangeMsg:

$limitTime = $actualTime - $this->idleLimit;
$users = dibi::fetchAll("SELECT username FROM users WHERE action > $limitTime");
$this->payload->users = $users;

a u klienta se v panelu uživatelů prostě vypíšou pouze ti aktivní:

var users = payload.users;
var chatUsers = $('#chatUsers');
chatUsers.empty();
for (i in users) {
	chatUsers.append('<li>'+users[i].username+'</li>');
}
i.magine
Člen | 81
+
0
-

Aha… no ja mam popravde stejnej problem: Nastavím session na +2 days a po zavreni prohlizece je prihlaseni fuc .

lactarius
Člen | 47
+
0
-

A máš určitě nastavenou jak expiraci session

bootstrap:

$session = Environment::getSession();
$session->setExpiration('+ 14 days');

tak uživatele ?

BasePresenter (třeba):

if ($memo) {
	$this->getUser()->setExpiration('+ 14 days', FALSE);
} else {
	$this->getUser()->setExpiration('+ 20 minutes', TRUE);
}
i.magine
Člen | 81
+
0
-

Tak to jsem nemel… kazdopadne porad to nebezi:

public function formLoginSubmitted(AppForm $form)
{
    try {
            $session = Environment::getSession();
            $session->setExpiration("+ 5 days");
		$user = Environment::getUser();
		$user->setAuthenticationHandler(new Users);
		$user->setExpiration('+ 5 days', FALSE);
      	$user->authenticate($form['username']->getValue(), $form['password']->getValue());
		$this->presenter->redirect('UserAdmin:default');

	} catch (AuthenticationException $e) {
			$form->addError($e->getMessage());
	}
 }

Když se podívám do cookies tak po opětovném zapnutí prohlížeče už je PHPSESSID pryč. A vždy se u něj nastavuje Doba platnosti na žádnou hodnotu.

Díky

Editoval i.magine (29. 1. 2010 12:06)

Ondřej Mirtes
Člen | 1536
+
0
-

Přenes to nastavení expirace session do bootstrapu, jak ti radí příspěvek nad tím.

i.magine
Člen | 81
+
0
-

Máš pravdu, funguje to… jenom nechápu jakej je rozdíl když to nastavím v bootstrapu a nebo v logovacím formuláři. Každopádně díky.

Honza Kuchař
Člen | 1662
+
0
-

@R2D2: a nemáš nastavenou menší expiraci session?

Nebylo vy fajn, kdyby to vyhazovalo výjimku?

Editoval honzakuchar (29. 1. 2010 13:17)

i.magine
Člen | 81
+
0
-

To by teda bylo :D

i.magine
Člen | 81
+
0
-

@R2D2: a nemáš nastavenou menší expiraci session?

Nemělo by se to dopsat do dokumentace? Trvalé přihlášení je dneska skoro povinnost a tohleto je docela zrada :-).