6 messaggi dal 10 luglio 2015
Ciao a tutti, vorrei chiedere una cosa riguardante il framework Identity di Asp .Net 4.5.

Sto sviluppando un'applicazione che per motivi commerciali deve accettare un solo login per account alla volta.
Ho effettuato diverse ricerche su internet per avere idee su come risolvere la questione e l'opzione più plausibile è quella di generare un token in fase di login salvarlo nel database e creare un cookie all'utente; se un altro utente provasse a collegarsi con le stesse credenziali verrebbe generato un nuovo token che non corrisponderebbe con quello nel database rilevando così il doppio-login.

Il problema principale che ho riscontrato con questo metodo è che si può facilmente copiare i cookies dell'utente già loggato su un altro browser/macchina e questo verrebbe accettato dall'applicazione come utente valido.

Per ovviare a questo problema sono giunto quindi alla conclusione di creare un token, salvarlo nel database e creare un cookie all'utente ad ogni richiesta... utilizzando un ActionFilter in questo modo:

public class UserActionFilter : ActionFilterAttribute
{
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            IIdentity userIdentity = filterContext.RequestContext.HttpContext.User.Identity;

            if (!userIdentity.IsAuthenticated) return;

            ApplicationUserManager userManager = filterContext.RequestContext.HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();

            ApplicationUser user = userManager.FindByNameAsync(userIdentity.Name).Result;

            if (user != null)
            {
                // Ottengo il token da un cookie già presente
                string getSvt = filterContext.HttpContext.Request.Cookies["__SessionVerificationToken"].Value.ToString();

                // Controllo che il token del cookie sia uguale a quello salvato nel db
                if (user.SessionToken == getSvt || user.SessionToken == null)
                {
                    // Genero un nuovo token...
                    string setSvt = Guid.NewGuid().ToString();

                    // ...lo mando all'utente
                    HttpCookie svtCookie = new HttpCookie("__SessionVerificationToken", setSvt);
                    svtCookie.HttpOnly = true;
                    filterContext.HttpContext.Response.Cookies.Add(svtCookie);

                    // ....lo salvo nel db
                    user.SessionToken = setSvt;
                }
                else
                {
// Se i tokens non coincidono forzo il SignOut e reindirizzo alla pagina di Login                    filterContext.RequestContext.HttpContext.GetOwinContext().Authentication.SignOut();
                    filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { 
                        { "controller", "Account" }, 
                        { "action", "Login" } 
                    });
                }

                // Aggiorno i dati dell'utente nel db con il nuovo token
                userManager.UpdateAsync(user).Wait();
            }
        }
}


La cosa sembra funziona ma mi sembra forse un po' troppo impegnativa in fatto di risorse... quindi vorrei chiedere a voi, sicuramente più esperti di me, cosa ne pensate e come potrei risolvere il problema.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,

wizzy ha scritto:

La cosa sembra funziona ma mi sembra forse un po' troppo impegnativa in fatto di risorse...

Non penso che sia così oneroso però, certamente, se puoi risparmiare due chiamate al database è preferibile.
Potresti tenere le corrispondenze tra username e codice in una cache, anziché nel database.
A questo c'è una controindicazione: se la cache è in memoria e devi riavviare il server, allora tutti gli utenti dovranno rifare il login al successivo riavvio della macchina perché ormai le corrispondenze saranno andate perdute. Per limitare il problema, potresti salvare le corrispondenze su db dall'evento Application_End e ripristinarle in cache al successivo Application_Start. Non è un meccanismo infallibile ma potrebbe essere un buon compromesso per ottenere prestazioni migliori da un algoritmo che va in esecuzione così di frequente nella tua applicazione.

Oppure - forse è preferibile - puoi valutare la cache di Redis e la sua opzione di persistenza RDB, così non devi preoccuparti tu di far sopravvivere le corrispondenze ad un riavvio.
http://redis.io/topics/persistence

ciao,
Moreno

PS. ASP.NET Identity ha già un meccanismo di signout che avresti potuto usare per invalidare il cookie. Lo vedi in questo articolo di Marco De Sanctis.
http://www.aspitalia.com/script/1180/Sign-Out-Remoto-ASP.NET-Identity.aspx
...ma non avrebbe risolto il problema, perché tu hai chiesto esplicitamente delle prestazioni migliori, e quelle probabilmente le ottieni leggendo da una cache anziché dal db.
Modificato da BrightSoul il 02 agosto 2015 22.43 -

Enjoy learning and just keep making
6 messaggi dal 10 luglio 2015
Grazie Moreno della risposta ma credo di risolvere in un altro modo, questo mi sembra un po' troppo complicato da gestire... sopratutto se arrivano diverse richieste AJAX che rischiano di sovrapporsi...
Ho deciso per contare le effettive connessioni al database, so che non è la stessa cosa ma a fini commerciali può andare bene lo stesso.
Modificato da wizzy il 06 agosto 2015 03.24 -

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.