Trvalé přihlášení – problém s cookies

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

Mám problém s trvalým přihlášením. Pro přihlášení do aplikace používám příklad z distribuce:

<?php
public function signInFormSubmitted($form) {
		try {
			$values = $form->getValues();
			if ($values['remember']) {
				$this->getUser()->setExpiration('+ 30 days', FALSE);
			} else {
				$this->getUser()->setExpiration('+ 30 minutes', TRUE);
			}
			$this->getUser()->login($values['email'], $values['password']);
			$this->redirect('Homepage:');

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

Pokud to chápu správně, tak by se měla platnost cookie „PHPSESSID“ nastavit na 30 dní. Ona má ale platnost pouze do konce sezení. V bootstrapu mám ještě nastaveno toto:

<?php
Environment::getSession()->setExpiration(30 * 24 * 60 * 60); // 30 days
?>
Šaman
Člen | 2659
+
0
-

Tohle skutečně znamená, že pokud při přihlášení zatrhneš „Remember me“, tak by měla být platnost 30 dní a nemazat cookies po skončeni prohlížeče. Ještě si zkontroluj jestli náhodou prohlížeč nemaže cookies sám (po zavření smazat historii).

Občas to někomu z neznámých důvodů zlobí

Filip Procházka
Moderator | 4668
+
0
-

Když nastavuješ platnost přihlášení, je ještě potřeba prodloužit platnost session. Její platnost může skončit dřív, než platnost SessionNamespace, ve kterém je uživatel uložený.

Aurielle
Člen | 1281
+
0
-

Ono je možné nastavit platnost session i po jejím spuštění? Řešením je nastavit session třeba na rok, a trvalé přihlášení na 2 týdny třeba…

Pancus
Člen | 14
+
0
-

Ať dělám co dělám, pořád mi cookie expiruje

Pancus
Člen | 14
+
0
-

Tohle asi neni správně, že?

<?php
$cookie = Environment::getSession()->getCookieParams();
Debug::dump($cookie);

//dump
array(5) {
   "lifetime" => 0
   "path" => "/"
   "domain" => ""
   "secure" => FALSE
   "httponly" => TRUE
}
?>
Pancus
Člen | 14
+
0
-

Vyřešeno. Session nebyl jaksi nastartovaná. Do bootsrtrapu jsem přidal:

<?php
if (!$session->isStarted()) {
  $session->start();
}
?>

Je to tak správně? Má to být v bootstrapu? Nebo někde jinde?
Toto mi přijde dost nejasně zdokumentované. Např. v Sandboxu v distribuci (ze které jsem trvalé přihlášení okopnul) jsem nenašel startování session. Chybí to tam?

Každopádně díky za nakopnutí!

Aurielle
Člen | 1281
+
0
-

Session by měla být startována automaticky, viz https://api.nette.org/…ion.php.html#97.

kucix
Člen | 33
+
0
-

Pancus napsal(a):

Vyřešeno. Session nebyl jaksi nastartovaná. Do bootsrtrapu jsem přidal:

<?php
if (!$session->isStarted()) {
  $session->start();
}
?>

Je to tak správně? Má to být v bootstrapu? Nebo někde jinde?
Toto mi přijde dost nejasně zdokumentované. Např. v Sandboxu v distribuci (ze které jsem trvalé přihlášení okopnul) jsem nenašel startování session. Chybí to tam?

Každopádně díky za nakopnutí!

Když jsem to použil, tak se vytvořilo přes 30000 session souborů a bylo využito celých 16GB RAM a k tomu ještě skoro 10GB swap …
Jen dodám, že normálně je využito tak 5–7GB RAM a 0 SWAP

Má někdo nějaké jiné řešení ?

srigi
Nette Blogger | 558
+
0
-

kucix napsal(a):

Asi sa jedna o tento problem.

Editoval srigi (7. 4. 2011 13:05)

kucix
Člen | 33
+
0
-

nj, ale jak to vyřešit …

řeším dva problémy:

  1. když to není v bootstrapu, tak po zavření prohlížeče jsem automaticky odhlášen (ano mám v botstrapu nastavenou hlavní session a + 14 days)
  2. když to dám do bootstrapu, tak přihlášení vydrží, ale zabije to nakonec server … díky iowaitu

Napsat si ukládání do databáze .. o tom jsem přemýšlel, ale DB je už tak celkem dost vytížená.

PS: stránka, na které to řeším má cca 100 000 uživatelů za den, 500 000 zobrazení za den …
V měsíčním průměru je to něco mezi 16M a 17M zobrazení … takže by to databázi určitě nepomohlo …

Michalek
Člen | 211
+
0
-

Řeším podobný problém, jen s o nulu kratším číslem. Jediné, na co jsem přišel, je rozvrstvit session do podadresářů, protože dle mýho zjištění největší problém dělá čtení tolika souborů v jednom adresáři. A snížit pravděpodobnost mazání starých. Pak zatížení serveru rapidně kleslo.

ini_set('session.save_path', '2;/var/www/session/'); //  http://goo.gl/zRH3I
ini_set('session.gc_divisor', 10000);
kucix
Člen | 33
+
0
-

In order to use N you must create all of these directories before use.

vypadá to, že musím vytvořit všechny podadresáře …

No .. každopádně uvidíme, nastavil jsem 3;/tmp :-)

Editoval kucix (7. 4. 2011 14:54)

Michalek
Člen | 211
+
0
-

Jo, v návodu je zmíněný nějaký skript který to umí sám.

kucix
Člen | 33
+
0
-

Stejně.. to je takové řešení … na prd …

pořád mi nejde do hlavy, proč musím obcházet startování session ve frameworku jeho manuálním startováním v bootstrapu…

Bez těch 3 řádků vše funguje jak má, uživatel je přihlášen, vše v pohodě.. až na to zavření prohlížeče, kdy ho to automaticky odhlásí …

Už přemýšlím i nad tím, jestli problém nebude v tom, že v BasePresenteru v metodě startup() volám $this->user = Environment::getUser();

srigi
Nette Blogger | 558
+
0
-

kucix napsal(a):

pořád mi nejde do hlavy, proč musím obcházet startování session ve frameworku jeho manuálním startováním v bootstrapu…

Nemusis. V bootstrap.php staci iba Environment::getSession()->setExpiration('+ 90 days');. Zvysok zariad podla mojho ACL tut. Takto to ide v pohode (session vydrzi restart browsera), netreba session manualne startovat. Moze sa vsak obcas objavit chyba headers already sent – pretoze, session sa staruje lazy. A ak spravis echo na vystup… (vsak to pozname).

kucix
Člen | 33
+
0
-

Nepotřebuji ACL, řeším to trochu jinak (Environment::getUser()->getIdentity()->data['rights'])

A přihlašují se všichni, ne jen admini, ale všichni uživatelé.

Při stavu, kdy proběhne odhlášení při zavření prohlížeče byl kód cca takto:

  1. bootstrap – Environment::getSession()->setExpiration("+ 14 days");
  2. BasePresenter – metoda startup(): $this->user = Environment::getUser();, v zápětí $this->user->isLoggedIn(); dokonce 2× … podruhé v metodě checkUser(), kde vyberu z DB uživatele podle údajů z getIdentity()->data[] a pokud se liší, tak zavolám $this->user->login($username, $password) (password je md5, nejsem blázen a nemám v session plaintext heslo …)

login mám přes svoji třídu – výtažek:

<?php
public function loginFormSubmitted(AppForm $form) {
	try {
		$values = $form->getValues();
		$user = Environment::getUser();
		$user->setExpiration( "+ 14 days", false);
		$user->login($values['username'], MyHash::hash($values['password']));
...atd...
?>

Teď po přidání do bootstrapu toho nastartování, které je výše, uživatel zůstane přihlášený i po zavření prohlížeče, jen se generuje velké množství sessions

teď jsem ještě zkusil dát na konec bootrstrapu, za spuštění aplikace:

<?php
if(!Environment::GetUser()->isLoggedIn()){
	Environment::getSession()->destroy();
}
?>

Ale to bude mít za následek jen to, že se pro nepřihlášeného (i robota) session na disku vytvoří a následně smaže… nebude takové množství souborů, ale stále je tu vysoký iowait díky vytváření sessions a jejich mazání…

Michalek
Člen | 211
+
0
-

Přesně tohle jako ty jsem dělal, ale bacha, přestanou fungovat formuláře (s ochranou proti CSRF). Včetně přihlašování.

Editoval Michalek (7. 4. 2011 18:50)

kucix
Člen | 33
+
0
-

mi fungují … → aumojekoule.eu

kucix
Člen | 33
+
0
-

Nikdo žádný další nápad?

Proč se nestartuje session v Nette sama?

Proč musím startovat manuálně … ?