LogOff with bank registration and cookie deletion behind Session_End () in Global.asax

2

I'm needing help with a project I've been breaking my head for two days. I am using Microsoft C # MVC5 technology and framework 4.5, I also use Entity Framework 6 with Repository Pattern, Unit of Work, and Unity to perform the dependency injection.

I have a controller called AccountController that is responsible for logging in and logging out the user on the system, this controller receives the application's repository methods through dependency injection through the builder.

AccountController

public class AccountController : BaseController
{
    private readonly IUsuarioApp _usuarioApp;
    private readonly IUnitOfWorkAsync _unitOfWorkAsync;

    public AccountController() { }

    public AccountController(IUsuarioApp usuarioApp, IUnitOfWorkAsync unitOfWorkAsync)
    {
        _unitOfWorkAsync = unitOfWorkAsync;
        _usuarioApp = usuarioApp;
    }

    // GET: Login
    [AllowAnonymous]
    public ActionResult Login()
    {
        return View();
    }

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Login([Bind(Include = "Email, Password")]LoginViewModel model, string returnUrl)
    {
        try
        {
            if (!ModelState.IsValid) return View(model);

            var usuarioAutenticado = _usuarioApp.AutenticarUsuarioPor(model.Email, model.Password);

            var logDeAcesso = new LogDeAcesso { DataDeAcesso = DateTime.Now, UsuarioId = usuarioAutenticado.Id };

            usuarioAutenticado.DataDoUltimoAcesso = logDeAcesso.DataDeAcesso;

            _usuarioApp.Update(usuarioAutenticado);
            _usuarioApp.GetRepository<LogDeAcesso>().Insert(logDeAcesso);
            _unitOfWorkAsync.SaveChanges();

            SessionContext.SetAuthenticationToken(usuarioAutenticado.Id.ToString(), false, ConvertToUsuarioViewModel(usuarioAutenticado));

            return RedirectToAction("Index", "Home");
        }
        catch (Exception ex)
        {
            ModelState.AddModelError("", "Tentativa de login inválido.");
            return View(model);
        }
    }

    public ActionResult LogOff(int id)
    {
        try
        {
            var ultimoLogsDeAcessoCriado = _usuarioApp.GetRepository<LogDeAcesso>().Query(model => model.UsuarioId == id).OrderBy(model => model.OrderByDescending(c => c.DataDeAcesso)).Select().FirstOrDefault();

            if (ultimoLogsDeAcessoCriado == null || ultimoLogsDeAcessoCriado.DataDeSaida != DateTime.MinValue) throw new Exception("Erro ao tentar deslogar do sistema.");

            ultimoLogsDeAcessoCriado.DataDeSaida = DateTime.Now;
            _usuarioApp.GetRepository<LogDeAcesso>().Update(ultimoLogsDeAcessoCriado);
            _unitOfWorkAsync.SaveChanges();

            FormsAuthentication.SignOut();
            Session.Clear(); //Pode não ser necessário, mas não é problemático o uso como prevenção
            Session.Abandon();

            //Limpar o cookie de Autenticação
            var resetFormsCookie = new HttpCookie(FormsAuthentication.FormsCookieName, "");
            resetFormsCookie.Expires = DateTime.Now.AddYears(-1);
            Response.Cookies.Add(resetFormsCookie);

            //Limpar a session cookie
            var resetSessionCookie = new HttpCookie("ASP.NET_SessionId", "");
            resetSessionCookie.Expires = DateTime.Now.AddYears(-1);
            Response.Cookies.Add(resetSessionCookie);

            //Invalida o Cache no lado do Cliente
            Response.Cache.SetCacheability(HttpCacheability.NoCache);
            Response.Cache.SetNoStore();

        }
        catch (Exception ex)
        {
            Danger("Error: " + ex.Message);
        }

        return RedirectToAction("Login", "Account");
    }


    #region Helpers

    private UsuarioViewModel ConvertToUsuarioViewModel(Usuario usuario)
    {
        return new UsuarioViewModel
        {
            Id = usuario.Id,
            Nome = usuario.Nome,
            UltimoAcesso = usuario.DataDoUltimoAcesso
        };
    }

    #endregion
}

As it is seen, when logging in the user is authenticated through the email and the password, an instance of the Access Log is created where we register the access date of the access and later the cookie is created where the cookie will be stored, which will allow the access the pages of the Site.

After obtaining the access, the user can click on the logoff button, in which it will trigger the ActionResult LogOff method that will get the last access log created based on the user id, update with the data of the System exit date, will clear the Session and Cookies by redirecting it to the Login page. From there he will only have access to the other pages if he re-logs in.

It dynamically works fine, but does it have a problem, and if the user does not click the logoff button, and instead, close the tab or browser? As it was built, it will remain authenticated in the 20-minute IIS defaults to cookie expiration time, not to mention that this way I will not be able to register the Exit Date in the Access Log. p>

Thinking about this, I configured a session timeout in Web.config

Web.Config


&ltconfiguration&gt
  &ltsystem.web&gt
    &ltcompilation debug="true" targetFramework="4.5" /&gt
    &lthttpRuntime targetFramework="4.5" /&gt
    &ltglobalization culture="pt-BR" uiCulture="pt-BR" /&gt
    &ltauthentication mode="Forms"&gt
      &ltforms loginUrl="~/Account/Login" timeout="2880" slidingExpiration="true" /&gt
    &lt/authentication&gt
    &ltsessionState
       mode="InProc"
       stateConnectionString="tcpip=127.0.0.1:42424"
       stateNetworkTimeout="20"
       sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI"
       sqlCommandTimeout="20"
       customProvider=""
       cookieless="UseCookies"
       cookieName="ASP.NET_SessionId"
       timeout="1"
       allowCustomSqlDatabase="false"
       regenerateExpiredSessionId="true"
       partitionResolverType=""
       useHostingIdentity="true"&gt
      &ltproviders&gt
        &ltclear /&gt
      &lt/providers&gt
    &lt/sessionState&gt
    &ltmachineKey validationKey="466AFE06F664B2E3662F97B81D30E87907F9921E51C95C618A670B396403AD98DD032BCE7610EEAE1FB1DA7B3ED7ACE56537E66FD6DF20E701351697E57C3D9C" decryptionKey="CD10ABC11246E6998AB7B9A8CC142CDD6C8AEF7FB12D15CF12158BEAD647C603" validation="SHA1" decryption="AES" /&gt 
  &lt/system.web&gt
&lt/configuration&gt

Only when timeout happens and I enter Global.asax in method Session_End() , I can not access repositories and FormsAuthentication .

I'd like to know what I have to do to repeat within Session_End() exactly what I do when I click the logoff button. Could someone help?

EDIT

Well, I think I can better elucidate what I'm looking for. I am trying to develop a way to make a database in the database and destroy the authentication ticket, Session and Cookie at the time the TimeOut of downtime occurs.

    
asked by anonymous 09.10.2014 / 22:20

2 answers

1

After much research, I came to the conclusion that it is impossible to logoff the way I do the button through Session_End() . The way I set up to clear the cookie after the timeout event, was done at Session_Start()


    protected void Session_Start()
        {
            try
            {
                var usuario = new SessionContext().GetUserData();

                if (usuario == null) return;

                Session.Clear(); //Pode não ser necessário, mas não é problemático o uso como prevenção
                Session.Abandon();

                //Limpar o cookie de Autenticação
                var resetFormsCookie = new HttpCookie(FormsAuthentication.FormsCookieName, "");
                resetFormsCookie.Expires = DateTime.Now.AddYears(-1);
                Response.Cookies.Add(resetFormsCookie);

                //Limpar a session cookie
                var resetSessionCookie = new HttpCookie("ASP.NET_SessionId", "");
                resetSessionCookie.Expires = DateTime.Now.AddYears(-1);
                Response.Cookies.Add(resetSessionCookie);

                //Invalida o Cache no lado do Cliente
                Response.Cache.SetCacheability(HttpCacheability.NoCache);
                Response.Cache.SetNoStore();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                Response.RedirectToRoute("Default");
            }
        }

And I left the following code in Session_End () as prevention.


    protected void Session_End()
    {
        Session.Clear();
        Session.Abandon();
    }
    
13.10.2014 / 14:38
1

You can redirect the request to a route that has access to what you need:

protected void Session_End()
{
    Response.Clear(); 
    RouteData routeData = new RouteData(); 

    routeData.Values.Add("controller", "Account"); 
    routeData.Values.Add("action", "Login"); 

    IController AccountMainController = new AccountController(); 
    AccountMainController.Execute(new RequestContext( 
            new HttpContextWrapper(HttpContext.Current), routeData));
}
    
09.10.2014 / 23:27