【问题标题】:Session Manager will not log me out when session expires, HTTPContext.Current is Null会话到期时,会话管理器不会注销我,HTTPContext.Current 为 Null
【发布时间】:2014-09-12 03:50:34
【问题描述】:

我当前的会话管理器遇到了这个问题,当会话到期时,它不会注销用户。

在用户登录时,HttpContext.CurrentNULL 的随机间隔,导致站点产生许多错误。我尝试了几种技术在会话到期时将用户重定向到登录,但没有成功。

  1. Global.asax下我正在使用Session_End可以尝试 调用 LogOut 方法,但这甚至在用户登录之前就被执行 在。
  2. Global.asax 下我添加了Application_AcquireRequestState,但遗憾的是,这让位于对SSO 服务的许多调用。此外,它永远不会在会话到期时重定向到登录。我用以下FormsAuthentication.RedirectToLoginPage()对其进行了测试;不走运。

我通过Lex Li "Why HttpContext.Current be null?" 找到了这个答案 - 它让我对我的问题可能有一些了解,即使我的应用程序没有使用后台线程,我的HttpContext.Current 又回来了一些随机请求的 null 并不总是发生。

会话管理器

   public class SessionManager
    {
        private const string SessionKey = "AppSession";

        private SessionManager()
        {
            GUID                  = new Guid();
            FirstName             = String.Empty;
            LastName              = String.Empty;
            Email                 = String.Empty;
            SessionExpiration     = new DateTime();
        }

        // Gets the current session.
        public static SessionManager Current
        {
            get
            {
                if(HttpContext.Current != null)
                {
                    if (HttpContext.Current.Session[SessionKey] == null)
                    {
                        var model = new SessionManager();
                        HttpContext.Current.Session[SessionKey] = model;
                    }
                    return (SessionManager)HttpContext.Current.Session[SessionKey];
                }
                else
                {
                    return null;
                }
            }

        }

        public static void LogOffUser()
        {
            //SSO is a seperate service, I need to stay insync.
            var ssoAuth = new SSOAuth(); 
            if(Current != null)
               ssoAuth.SSOLogoffUser(Current.GUID);

            FormsAuthentication.SignOut();  
            FormsAuthentication.RedirectToLoginPage();
        }

        public Guid GUID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public DateTime SessionExpiration { get; set; }
    }

登录控制器

[HttpPost]
[AllowAnonymous]
public JsonResult Login(LoginViewModel user)
{
    var ssoAuth = new SSOAuth();
    var sessionObject = ssoAuth.SSOLoginUser(user.Email, user.Password);

    if (sessionObject != null && sessionObject.SessionId != Guid.Empty)
    {
        SessionManager.Current.Email                 = sessionObject.UserId;
        SessionManager.Current.GUID                  = sessionObject.SessionId;
        SessionManager.Current.FirstName             = sessionObject.FirstName;
        SessionManager.Current.LastName              = sessionObject.LastName;
        SessionManager.Current.SessionExpiration     = sessionObject.SessionExpiration;

        //Grab difference in time to get session timeout in minutes.
        var differenceInTime = SessionManager.Current.SessionExpiration - DateTime.Now;
        Session.Timeout = differenceInTime.Minutes;

        //Authenticate user
        FormsAuthentication.SetAuthCookie(user.Email, false);

        //We return JSON, Its an AJAX Call.
        return Json(new
        {
            redirectUrl = "/Home.mvc/Home/Index",
            isRedirect = true
        });
    }

    return Json(new
    {
        redirectUrl = string.Empty,
        isRedirect = false
    });
}

【问题讨论】:

  • HttpContext.Current 永远不应为 null,除非在 Application_Start() 中,如果是,您必须在某处将其设置为 null。这只是不正常的情况。如果我是你,我会对 HttpContext 进行全局搜索并目视检查每个位置,以确保你没有在某处使用单个 = 而不是 ==。
  • 您也不应该使用会话进行身份验证。会话不安全。另外,如果您的应用程序池被回收,您会丢失会话,但您的身份验证 cookie 仍然有效,因此事情将不同步。
  • @ErikFunkenbusch 谢谢你的意见,我现在正在全球搜索,我找不到任何设置HttpContext,它正在使用但没有改变。另外,您对身份验证有何建议,我将用户信息存储在会话中,以确保其在全球范围内使用并与网络服务同步。
  • 好吧,我会将大部分信息存储在 Auth Cookie 的用户数据部分。您已经在 auth cookie 中有用户 ID,因此不必保存,您可以将 cookie 的到期时间设置为与 SessionExpiration 相同,这样就不需要保存,只留下 FirstName、LastName 和指导。见danharman.net/2011/07/07/…
  • @ErikFunkenbusch 我正在阅读这篇文章,谢谢!请,为什么不将其发布为答案,如果我在该文章中的实施进展顺利,我可以接受您的答案。

标签: c# asp.net asp.net-mvc forms-authentication session-management


【解决方案1】:

正如 cmets 中所确认的,您将应用程序池的 Maximum number of worker processes 设置为 高于 1 的值,并将 In-Process Mode 用于会话状态。

我很确定这是 HttpContext.Current.Session 随机为空而不是 HttpContext.Current 的问题。

InProc 会话状态和multiple working processes 不兼容。使用InProc 会话状态,您的会话状态存储在工作进程内存中并且在工作进程之间不共享 =>当您的请求由不同的进程提供服务时,这会导致会话状态随机丢失。

在您的情况下,将 Maximum number of worker processes 设置为 1 应该可以解决问题。

如果您正在寻找多工作进程解决方案,您应该使用会话状态服务或数据库将会话状态存储在进程外:http://tutorials.csharp-online.net/ASP.NET_State_Management%E2%80%94Storing_Session_State_out_of_Process

【讨论】:

  • 对不起,我弄错了,我刚刚去了 IIS,我确实将 Maximun Worker Processes 设置为 1。另外请注意,确实是 HttpContext.Current 是 Null...保留不过,这个答案是非常好的信息,肯定会对某人有所帮助。
【解决方案2】:

这听起来很可疑,可能是会话与表单身份验证时间问题,类似于 Forms Authentication Timeout vs Session Timeout

确保您的表单超时至少是会话超时的 2 倍。

【讨论】:

  • 谢谢你,它确实帮助我纠正了问题!
【解决方案3】:

我认为您可能需要验证您的 web.config 中是否设置了此设置

<httpRuntime targetFramework="4.5" />

您似乎没有任务友好等待,这会导致诸如此类的意外行为。你可以参考similar problem这里提出的and the solution

现在,您可能没有在您的解决方案中使用异步代码,但这并不意味着框架没有使用它。无论如何,我认为值得一试。

【讨论】:

    猜你喜欢
    • 2014-08-15
    • 2014-07-08
    • 2018-01-30
    • 2015-02-10
    • 1970-01-01
    • 1970-01-01
    • 2012-04-19
    • 2019-07-04
    • 2011-11-14
    相关资源
    最近更新 更多