简体   繁体   English

在数据库中注销日志并在Global.asax中的Session_End()后面删除cookie

[英]With LogOff record in database and deleting cookie behind the Session_End ( ) in Global.asax

I am needing help in a project I'm breaking my head for two days. 我在为期两天的工作中需要帮助。 I am using Microsoft C # MVC5 technology and framework 4.5, also use Entity Framework 6 with Repository Pattern, Unit of Work and Unity for the realization of dependency injection. 我正在使用Microsoft C#MVC5技术和框架4.5,还使用带有存储库模式,工作单元和Unity的Entity Framework 6来实现依赖项注入。

I have a controller called AccountController that is responsible for performing the login and logoff user on the system, the controller receives the methods of the repository by applying dependency injection by the same Construtor. 我有一个称为AccountController的控制器,该控制器负责在系统上执行登录和注销用户,该控制器通过应用同一构造者的依赖项注入来接收存储库的方法。

AccountController 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

}

Is seen as the login, the user is authenticated via email and the password is created an instance of the Access Log is registered where the entry access and is subsequently created the cookie will be stored where the cookie will allow the access Application pages. 被视为登录,通过电子邮件对用户进行身份验证,并创建密码,在访问日志的实例中注册该条目的访问权限,随后创建cookie,该cookie将存储在cookie允许访问应用程序页面的位置。

After obtaining access, the user can click the logoff button, which launches the ActionResult LogOff method that will get the last log created access based on the user id, update the data with the DataDeSaida LogDeAcesso, clear the Session and Cookies, redirecting it to the Login page. 获得访问权限后,用户可以单击注销按钮,该按钮将启动ActionResult LogOff方法,该方法将基于用户ID获得上次创建日志的访问权限,使用DataDeSaida LogDeAcesso更新数据,清除会话和Cookies,然后将其重定向到登录页面。 From there he will only have access again the other pages if he perform the login again. 如果他再次执行登录,则只能从那里再次访问其他页面。

Is dynamic works very well, but has a problem, and if the user does not click on the button off, and instead settle close the tab or the browser? 动态效果是否很好,但是存在问题,并且如果用户没有单击关闭按钮,而是选择关闭选项卡或浏览器? Forms that was built, he will remain logged in 20 min standards IIS defaults to downtime, but the expiration time of the cookie, not to mention that this way I will not be able to register DataDeSaida in LogDeAcesso. 建立表单后,他将保持20分钟的标准状态(默认情况下,IIS将默认为停机时间),但cookie的过期时间更是如此,更不用说以这种方式,我将无法在LogDeAcesso中注册DataDeSaida。

Thinking about it I configured in the Web.config a timeout interval in the Session 考虑一下,我在Web.config中配置了Session中的超时间隔

Web.Config Web配置

&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 the timeout happens and I get on the Global.asax Session_End() method, I can not access repositories and neither the FormsAuthentication . 仅当发生超时并且使用Global.asax Session_End()方法时,我才能访问存储库,也不能访问FormsAuthentication

I've tried to redirect the Session_End() to ActionResult Logoff using the following code 我尝试使用以下代码将Session_End()重定向到ActionResult注销

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));

However when passing through the line AccountMainController.Execute(new RequestContext (new HttpContextWrapper(HttpContext.Current), RouteData)); throws an exception of type ArgumentNullException: "Value can not be null Parameter name: httpContext 但是,当通过行AccountMainController.Execute(new RequestContext (new HttpContextWrapper(HttpContext.Current), RouteData)); throws an exception of type ArgumentNullException: "Value can not be null Parameter name: httpContext AccountMainController.Execute(new RequestContext (new HttpContextWrapper(HttpContext.Current), RouteData)); throws an exception of type ArgumentNullException: "Value can not be null Parameter name: httpContext . AccountMainController.Execute(new RequestContext (new HttpContextWrapper(HttpContext.Current), RouteData)); throws an exception of type ArgumentNullException: "Value can not be null Parameter name: httpContext

I wonder what I have to do to repeat within the Session_End() exactly what I do by clicking the logoff button. 我不知道我该怎么做才能在Session_End()重复单击注销按钮来执行的操作。 Could anyone help? 有人可以帮忙吗?

After much research, I concluded that it is impossible to perform "log off" in the same way that I perform when clicking the button in Session_End() , the way I arranged to clear the cookie, after the timeout event, was writing following code in Session_Start() . 经过大量研究,我得出结论,无法以与单击Session_End()的按钮时执行的相同方式执行“注销”,在超时事件之后,我安排清除cookie的方式是编写以下代码在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 as prevention, I wrote the following code in Session_End() . 为了预防起见,我在Session_End()编写了以下代码。



    protected void Session_End()
    {
        Session.Clear();
        Session.Abandon();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM