Forms authentication a session state - proč nejsou synchronní?

Ticket vystavení forms authentication modulem má danou platnost v minutách a lze nastavit, že bude "sliding", tedy že platnost bude prodlužována při každém požadavku. Stejně tak session timeout se udává v minutách a také se prodlužuje při každém požadavku. Zdravý rozum tedy říká, že pokud oba parametry nastavím na stejnou hodnotu, budou tickety i sessions platit vždy stejnou dobu. Leč, není tomu tak. Pojďme se podívat na to, jak tyto mechanismy vlastně fungují.

Forms authentication

Mechanismus forms authentication funguje tak, že se uživateli při přihlášení vystaví "autentizační ticket", který pak předává s každým požadavkem serveru a server dokáže podle něj uživatele ověřit. Tento ticket má z bezpečnostních důvodů časově omezenou platnost. Délka platnosti se nastavuje pomocí konfiguračního atributu timeout a standardně je dlouhá 30 minut.

Pomocí konfiguračního atributu slidingExpiration můžete určit, od kterého okamžiku se tento čas bude počítat. Ve výchozím nastavení (true) platí, že pokud uživatel pokládá požadavky na aplikaci, platnost ticketu se průběžně prodlužuje. Často se to zjednodušeně vykládá tak, že platnost autentizačního ticketu je timeout minut od posledního požadavku. Nastavíte-li slidingExpiration na false, platnost ticketu se neprodlužuje a platí timeout minut od přihlášení.

Implementace slidingExpiration je ovšem taková, že se ticket neobnovuje při každém požadavku, ale pouze tehdy, pokud již uplynula nejméně polovina jeho doby platnosti. Tato konstrukce tam je ze dvou důvodů: Internetový prohlížeč lze zpravidla nastavit tak, aby se při příchodu cookie (kde se autentizační ticket většinou ukládá) zeptal uživatele, zda ji chce přijmout, nebo nikoliv. Pokud by se při každém požadavku cookie obnovila, musel by uživatel tento dotaz zodpovídat neustále. Druhý důvod je výkonnostní: standardní implementace forms authentication funguje tak, že tvorba ticketu je relativně náročná, neboť je nutné ho zašifrovat a digitálně podepsat.

Session state

Session state má timeout také. Standardně je nastaven na 20 minut a počítá se od posledního požadavku na stránku. Přesněji řečeno: od posledního požadavku na HTTP handler, který session vyžaduje (implementuje interface IRequiresSessionState). Což sice standardně jsou všechny web formy (*.aspx), ale nemusí to být třeba váš generický handler (*.ashx).

Co z toho vyplývá

Následující diagram zobrazuje situaci, která může nastat, pokud nastavíme platnost autentizačního ticketu i session na stejnou dobu - 20 minut.  Při prvním požadavku v čase T = 0 se vystaví autentizační ticket, který vyprší v T+20 a stejně tak se vytvoří nová session, která bude platná stejnou dobu.

Pokud přijde v čase T+5 požadavek na běžnou stránku, prodlouží se řádně platnost session, která tedy vyprší až v čase T+25. Nicméně platnost autentizačního ticketu se neprodlouží, protože dosud neuplynula polovina doby jeho platnosti. Pokud tedy další požadavek přijde v době T+20 až T+25 (zvýrazněna žlutě), session bude stále k dispozici, ale uživatel už bude odhlášen.

Druhý diagram zachycuje opačnou situaci. Počáteční stav je stejný, platnost ticketu i session začala v čase T=0. V čase T+15 přijala aplikace požadavek na stránku, která ale nevyžaduje session - handler neimplemenuje IRequiresSessionState. V takovém případě se sice prodlouží platnost autentizačního ticketu, ale nikoliv session. Pokud přijde další požadavek v čase T+20 až T+35 (opět zvýrazněn žlutě), dojde k opačné situaci, než minule. Uživatel bude přihlášen, ale session již nebude k dispozici a založí se nová (na diagramu se tak stalo v čase T+25).

Mechanismy forms authentication a session state jsou na sobě naprosto nezávislé. Ukázali jsme si, že i při stejném nastavení hodnot timeout může nastat situace, kdy jedna z funkcí bude k dispozici a druhá nikoliv.

Řešení je nasnadě: nepoužívejte session. A pokud už se rozhodnete ji používat, tak se nespoléhejte na to, že bude s čímkoliv synchronní, bez ohledu na to, jak nastavíte timeout.

Titulek:
Text komentáře:
Vaše jméno:
Váš e-mail: (nebude zveřejněn)

WWW stránka:
Opište text z obrázku:

Pozor na zmatečnost některých verzí dokumentace frameworku (tuším SDK 2.0), kde bylo popsáno, že default hodnota vlastnosti slidingExpiration je false.

Pokud máme scénář, kdy dáváme do Session nějaké informace o přihlášeném uživateli (a pro náš scénář je nepoužitelný mechanizmus profilů, který je na to určený), pak je vhodným kontrolním bodem synchronizace událost Session_Start, která probíhá až po AuthenticateRequest, a kde můžeme dočíst informace pro ztracenou (novou) Session.

odpovědětodpovědět Gravatar

RE: Osobní zkušenosti

Ano presne tak, ja osobne docitavam informacie, ak My.User.IsAuthenticated.

odpovědětodpovědět Gravatar

RE: Osobní zkušenosti

Odzkoušeno, plně funkční.. Myslím, že ze dvou timeout je horší vypršení session, jakmile je platny forms ticket a session vypršela tak aplikace padne při prvním přístupu do sessiony.

odpovědětodpovědět Gravatar

Nepotěšil jste mě, ani já Vás nepotěším

Hezké, to může být docela průšvih:(

odpovědětodpovědět Gravatar

Ako zachytit vyprsanie session?

Ako zachytit vyprsanie session? Vo Web.config mam zadane <sessionState mode="InProc" cookieless="AutoDetect" timeout="1"></sessionState>, ale nic sa nedeje. Session.Abandon sa zachyti. Chcem identifikovat prihlasenych uzivatelov, takze ich musim nejako aj odhlasit.

odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

Vypršení session v podstatě nezachytíte. Existuje sice událost, která by se v tomto případě měla zavolat, ale na to se nemůžete spolehnout - třeba pokud se recykluje worker proces, tak se nemusí zavolat.

Kromě toho, uživatele nijak odhlásit nemůžete. Standardní autentizační ticket je prostě platný po celou dobu a nelze jeho platnost ukončit předčasně. I pokud uživatel klepne na "logout", je ticket stále platný, jenom server klientovi pošle zdvořilou prosbu, aby vymazat odpovídající cookie (například).

V případě session se nemůžete spolehnout ani na to, protože v okamžiku vypršení session nemáte klienta k dispozici, takže mu nemůžete poslat ani tu pokornou žádost, o které jsem psal výše.

Jinými slovy: sessions a forms authentication jsou technologie naprosto nezávislé a neexistuje způsob, jak je učinit synchronními. Nejlepší je sessions nepoužívat vůbec a když už na tuto dobrou radu nedáte, tak buďte připraveni na odobné roztomilosti.

odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

Vdaka za radu. Su to zaujimave dolezite malickosti. Dospel som teda k nazoru, ze zobrazeni online uzivatelov, zapisania prihlasenia a odhlasenia, sa da urobit len pomocou zachytenia casu poslednej poziadavky do db, ci javascriptom na stranke. Napada ta nejaka ina alternativa?

odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

A aby som nevyzeral, ze na vsetko som prisiel sam, vdacim aj zopar ludom na http://forum.builder.cz/read.php?31,2466… :).

odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

Zobrazení online uživatelů je principiální pitomost, protože HTTP je protokol bezstavový, takže nevíte, kdo je online. Maximálně můžete sledovat čas posledního požadavku a určit, že za "online uživatele" budete považovat ty, kdo vznesli požadavek v posledních n minutách - což ale nemá moc praktický význam.

Zapsání přihlášení můžete zařídit poměrně snadno, odstatně, dělá to přímo membership provider.

Zapsání odhlášení můžete provést pouze tehdy, pokud vám uživatel explicitně klikne na "odhlásit se" (což většinou neudělá). Pokud se výslovně neodhlásí, ale prostě jde jinam, nebo zavře okno prohlížeče, tak se o tom vůbec nedozvíte a opět musíte věštit. Kromě toho, u standardní forms authentication vám nepomůže ani to odhlášení, protože ticket prostě platí do vypršení a nazdar. Takže i poté, co se uživatel odhlásil, může znovu vystupovat jako autentizovaný -- aniž by se znovu přihlásil.

Použití JavaScriptu nedoporučuju, nedá se na něj spolehnout.

odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

Proc jako pitomost? Ja vim ze je jako bezstavovy a ze chcem s nim narabat ako s win forms, ale proc by to jako nemelo jit? Preco by sa podla teba nemalo dat na JS spolajnut? Co sa tyka odhlasenia podla uzivatela v tom nevidim problem, odhlasi sa zapisem do DB, ale ak presne ako pises nastane iny stav aplikacia nevie kedy odisiel zo stranky... tak presne to som chcel vyriesit automatickym session.abandon, mno a to nende. Takze ake existuju este alternativy? Iba podla poslednych poziadavkov. Vyjadrujes nazor ze to nema valny vyznam, ale precoze nie? Niekomu to staci vediet priblizny pocet. Ono stacilo by mi keby som vedel korektne odhlasit uzivatela, z toho sa da odcitat kto je prihlaseny, ale v tom je presne ten hacik, ako to vyriesit...

odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

Na JS se nedá spolehnout, protože z různých důvodů nemusí proběhnout - zejména takové ty skripty spouštějící se při přechodu na jinou stránku nebo zavření okna. Někdo nemá zapnutý JavaScript, zablokuje mu to nějaký blokátor reklamy, killne natvrdo prohlížeč, spadne mu spojení....

S odhlášením je taky problém, protože standardní forms authentication uživatele odhlásit v podstatě neumí, autentizační ticket je platný do expirace a nazdar. O tom mám právě rozepsaný podrobnější článek, vydržte.

Takže v praxi napíšete strašně komplikovanou věc, na jejíž výstupy se ale vůbec nemůžete spolehnout.

odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

25.3.2008 23:09:1225.3.2008 23:09:12 crustercruster ---.orange.sk
akuze komplikovanu? je to celkom jednoduche: void Application_Start(object sender, EventArgs e) { Application["ActiveUsers"] = 0; } void Session_Start(object sender, EventArgs e) { Application.Lock(); Application["ActiveUsers"] = Convert.ToInt32(Application["ActiveUsers"]) + 1; Application.UnLock(); } void Session_End(object sender, EventArgs e) { Application.Lock(); Application["ActiveUsers"] = Convert.ToInt32(Application["ActiveUsers"]) - 1; Application.UnLock(); } a predchadzajucimi komentarmi ste zrejme na mysli to, ze Session_End sa nemusi zavolat vzdy nuz, mam taketo riesenie nasadene na vcelku velkej aplikacii (denne radovo stovky simultanne pracujucich pouzivatelov) a funguje bez problemov - teda nikdy, ked som sa do aplikacie prihlasil po pracovnej dobe, neviseli tam ziadne neukoncene sessny
odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

25.3.2008 23:13:3525.3.2008 23:13:35 crustercruster ---.orange.sk
hops, zabudol som
odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

25.3.2008 23:18:1425.3.2008 23:18:14 crustercruster ---.orange.sk
okay, tak teda takto: http://pastebin.com/m17bbeb2d bez nahladu komentara je to teda riadna bieda
odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

A k čemu vám tahle konstrukce je v praxi dobrá?

odpovědětodpovědět Gravatar

RE: Ako zachytit vyprsanie session?

25.3.2008 23:30:1725.3.2008 23:30:17 crustercruster ---.orange.sk

na orientacne spocitanie pouzivatelov pracujucich s aplikaciou, co je informacia vyuzitelna v roznych situaciach

ak napr. nepracuje nikto, tak bez obav mozem zacat nasadzovat novy release bez toho, aby mi niekto rozhorcene telefonoval, ze pracoval a zrazu mu aplikacia padla

  • Altairis
  • Nemesis
  • Microsoft MVP
  • IIS
  • ASP.NET