Jak to přihlašování vlastně funguje (session/cookie)

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

Ahoj,

mám tu takový problém… Předně si potřebuju ujistit jak přihlašování v nette funguje, abych ze sebe neudělal uplnýho blbce :).

Měl jsem zato, že uživateli se vytvoří nějaký token. Ten se uloží na server společně s identitou do session (UserStorage). Uživatel má v cookies pouze tento token.

Když pak přijde uživatel na stránku třeba po týdnu z cookie se načte token „spáruje“ se s session a uživatel je přihlášen.

To je i důvod proč je nutné mít session session.gc_maxlifetime nastavenou na poměrně dlouho, třeba ten týden.

Z toho mi vychází že by mělo být celkem běžné mít na hostingu možnost session.gc_maxlifetime nastavit třeba na ten týden.

Funguje to takhle?

Filip Procházka
Moderator | 4668
+
0
-

Ten token se jmenuje SESSION ID a hostingu je to celkem jedno, dokud ti dovolí měnit si to na úrovni aplikace.

Ani
Člen | 226
+
0
-

Jop tu funkci jsem zkoumal a oni mi i to dovolí, ale napsali mim že ‚gc_maxlifetime‘ třeba 14 dní neni normální a jejich limit je 18 hodin…

Což mě teda normální nepřijde a jestli se nepletu, tak to ruší to možnost trvalého přihlášení v Nette?

Editoval Ani (12. 4. 2012 17:22)

Filip Procházka
Moderator | 4668
+
0
-

Tak ono jde o to, že ten garbace collector maže nepotřebná data. Kdyby jim tam každý uprdnutí trčelo dva týdny, tak se jim to nemusí líbit.

Řešit se to dá tak, že session budeš ukládat do nějaké databáze, tam ti je jedno jak je nastavený hosting.

Ani
Člen | 226
+
0
-

Tak to bych čekal že budou řešit u nějakého sdíleného lowcost hostingu ne u vps. No alespoň jsem se ujistil, že to funguje jak jsem myslel, pro zatím asi ubastlím nějaké vlastní ISessionStorage než se přesunem jinam.

Každopádně díky za odpovědi.

Tomáš Votruba
Moderator | 1114
+
0
-

Díky za nakousnutí tématu. Mám s trvalým přihlášením problém. Zmíněnou direktivu jsem zkusil a vrací mi 1440, což by zhruba odpovídalo.

Má Nette pro tyto účely nějakou spešl cookie? Případně existuje nějaký doporučený způsob jak trvalé přihlášení realizovat? Díky.

Ani
Člen | 226
+
0
-

Co jsem to zkoumal tak tam nic takového není. Napadlo mě přepsat si UserStorage, ale tam je to na tu session docela vázané, takže by to chtělo asi i vlastního Usera a určitě ještě něco, nějaké čísté jednodcuhé řešení tam nevidím.

Já jsem si udělal to ISessionStorage jak zmiňuji nahoře, trochu jsem si upravil tohle, takže teď ukládám session do sqlite:
https://forum.nette.org/…gu-a-priorit#…

btw. Já hostuju na savane, když tam dáš větší číslo jak 18 hod tak tam zůstavá výchozích 1440…

Tomáš Votruba
Moderator | 1114
+
0
-

Konečně, já taky na Savaně! :) Díky, ještě jsem koukal sem: https://forum.nette.org/…eulozi-do-db#….

Mohl bych tě požádat o tvé řešení? Zatím jsem se dostal tak daleko, že se připojím k db a něco zaznamenám. Když se ale zkusím přihlásit, tak zůstanu nepřihlášený.

Díky za návod!

Editoval Schmutzka (16. 4. 2012 1:56)

Ani
Člen | 226
+
0
-

Pužívám verzi nette 2.0.3

V bootrapu nic se session nemám, vše řeším v configu.

Start session na smart.

Jednak si nastavim sessionStorage, která se pak automaticky přidává do setStorage(), configurator ho přidá podle typehintu ISessionStorage automaticky.

No a jako druhé si vytvořim vlastní session, kde volám, už zmíněny setStorage, nějakou cestu pro db a setExpiration ta je důležitá, protože sice neovlivní session, ale nastavuje i expirace cookies, viz HosipLanem zmíněná funkce ve druhém příspěvku.

	nette:
		session:
			autoStart: smart

	services:
		sessionStorage:
			class: Services\SessionStorage

		session:
			setup:
				- setStorage()
				- setSavePath("%tempDir%/session.dbs")
				- setExpiration(+ 30 day)

SessionStorage

<?php
namespace Services;

/**
 * SessionStorage
 *
 */
class SessionStorage implements \Nette\Http\ISessionStorage {
  /**
     * Holds the database connection
     * @var \dibiConnection
     */
    private $conn = null;

    public  function open($savePath, $sessionName) {
        if (is_null($this->conn)) {
            $this->conn = \dibi::connect(array('driver' => 'sqlite', 'database' => $savePath));
         //   \dibi::activate(MainConnectionName);
        };
    }

    public  function read($id) {
        if (is_null($this->conn)) {
            throw new \Nette\InvalidStateException("The connection to database for session storage is not open!");
        };

        $query = '
            SELECT
                [data]
            FROM [session]
            WHERE
                [id] = %s';
        try {
            $result = $this->conn->query($query, $id);
            return $result->fetchSingle();
        } catch (\Exception $e) {

            $this->conn->query('CREATE TABLE [session] ([id] varchar(32) not null primary key, [timestamp] timestamp not null, [data] text)');
            $this->conn->query('CREATE INDEX [session_by_timestamp] ON [session] ([timestamp])');

            return '';
        };
    }

    public  function write($id, $data) {
        if (is_null($this->conn)) {
            throw new \Nette\InvalidStateException("The connection to database for session storage is not open!");
        };

        $this->conn->begin();
        $this->conn->query('DELETE FROM [session] WHERE [id] = %s', $id);
        $this->conn->query('INSERT INTO [session] VALUES(%s, %s, %s)', $id, time(), $data);
        $this->conn->commit();
    }

    public  function destroy($id) {
        if (is_null($this->conn)) {
            throw new \Nette\InvalidStateException("The connection to database for session storage is not open!");
        };

        $this->conn->query('DELETE FROM [session] WHERE [id] = %s', $id);
    }

    public  function clean($max) {
        if (is_null($this->conn)) {
            throw new \Nette\InvalidStateException("The connection to database for session storage is not open!");
        };

        $old = (time() - $max);
        $this->conn->query('DELETE FROM [session] WHERE [timestamp] < %s', $old);
    }

    public  function close() {
        $this->conn = null;
    }

	public function remove($id) {

	}

}
?>

Jestli se nepletu, tak nic víc jsem neměnil. Pak si to teda chce ještě nějak ošetřit to mazaní a tak, ale to přihlášení mi takhle chodí.

PS. můžeš je s tím taky otravovat na helpdesku, třeba se proberou a změní to zpět na nějou použitelnou hodnotu… :)

Editoval Ani (15. 4. 2012 20:54)

Tomáš Votruba
Moderator | 1114
+
0
-

To jsem už předevčírem, uvidíme :). Díky moc, přihlášení jede, nasadil jsem pro testovací provoz.

Je nějaké srovnání pro sqlite? Nešlo by to např. přímo v db rychleji? Ptám se, protože už po prvním přihlášení má nový soubor 14 kB.

EDIT: Aha, tak jsem to změnil v nastavení VPS a už to jde. Jen teď nevím, k čemu je potřeba vlastní třída. Pouhé nastavení VPS bez ní by trvalé přihlášení neumožnilo?

Editoval Schmutzka (16. 4. 2012 13:42)

Ani
Člen | 226
+
0
-

Jde nastavit max 64800s tj. 18 hodin a to je nedostatečné, alespoň pro mě…

DB by možná rychlejší byla, když se tam ten web už připojí, ale mě se část stránek díky cache do db vůbec nepřipojuje a tam bude rychlejší ta sqlite.

Nějaký testy a srovnaní jsem zatím neřešil. Beru to jako provizorní řešení, s tim že se uvidí co to bude dělat.

Filip Procházka
Moderator | 4668
+
0
-

Až teď jsem si to přečetl… Vy řešíte problém s nastavením VPSka? A to jako myslíte smrtelně vážně? A to jako u takového hostingu dobrovolně zůstáváte? Čím dřív přejdete, tím méně dat budete migrovat ;)

Ani
Člen | 226
+
0
-

Vždyť píšu že je to dočasné než půjdeme jinam… Ono není jednoduché vybrat něco pořádného, aby jsme nebyli za měsíc tam kde teď..

stekycz
Člen | 152
+
0
-

Zkoušel jsem tohle řešení použít upravené pro použití normální databáze a nechtělo mi to fungovat. Bylo pořeba přidat třídě destruktor asi takhle:

public function __destruct() {
	session_write_close();
}

Abych pravdu řekl, tak nechápu moc proč. Dokonce i podle PHP dokumentace by se tahle metoda měla volat při ukončení skriptu automaticky. Používám PHP 5.3.10.
Když jsem například v Presenteru zkusil zavolat $this->context->session->close();, tak mi to schodilo Apache.

Bernard Williams
Člen | 207
+
0
-

Nazdárek,

jak prosím metodě open($savePath, $sessionName) předám objekt \Nette\Database\Connection $connection nebo aspoň config? Pouhé předání konstruktorem nestačí – nebo spíš funguje, ale jen u metod write() a remove().

Řeším to kvůli hostingu SAVANA.cz, kde se nedá nastavit potřebná životnost session.

Budu rád za každou radu nebo nápad.

Díky
Bernard