【问题标题】:Constantly Loosing Session State ASP.NET不断丢失会话状态 ASP.NET
【发布时间】:2016-10-21 02:35:27
【问题描述】:

我的网站不断失去其会话状态并让用户退出,我不知道为什么。

我有一个操作过滤器,它会尝试检查 UserSession 是否仍然存在,如果不存在,它会检查用户是否经过身份验证,并尝试根据经过身份验证的用户 ID 恢复用户会话。

如果用户未通过身份验证,我会将他们重定向到登录页面。我还有一些代码可以检查它是否是 ajax 请求并手动将状​​态码设置为 403,以便我的 ajax 调用可以识别此状态并在 javascript 端进行重定向。

这是我的动作过滤器:

public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            SecuredController baseController = filterContext.Controller as SecuredController;

            //  Check if the session is available
            if (filterContext.HttpContext.Session["UserSession"] == null)
            {

                if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
                {
                    if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
                    {
                        filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
                        filterContext.Result = new JsonResult
                        {
                            Data = new { Error = "Unavailable", Url = "~/Account/Login" },
                            JsonRequestBehavior = JsonRequestBehavior.AllowGet
                        };
                        return;
                    }
                    if (!string.IsNullOrEmpty(HttpContext.Current.Request.RawUrl))
                    {
                        string returnUrl = HttpUtility.UrlEncode(HttpContext.Current.Request.RawUrl);
                        HttpContext.Current.Response.Redirect("~/Account/Login?returnUrl=" + returnUrl);
                    }
                    else
                    {
                        HttpContext.Current.Response.Redirect("~/Account/Login");
                    }
                }

                string userId = filterContext.HttpContext.User.Identity.GetUserId();

                Web.Helpers.Common common = new Helpers.Common();
                UserSession userSession = common.GetUserSession(userId);

                filterContext.HttpContext.Session["UserSession"] = userSession;
            }

            //  Set the Current user to the session variable
            baseController.CurrentUser = (UserSession)filterContext.HttpContext.Session["UserSession"];

            //  Continue executing the relevant action
            base.OnActionExecuting(filterContext);
        }

这是我的 Javascript 代码:

$.ajax({
            type: method,
            url: rootUrl + serviceUrl,
            async: aSync,
            data: dataParameters,
            cache: false,
            beforeSend: function () {
                if (targetProgressContainer === undefined) {
                    return;
                }
                if ($(targetProgressContainer).length === 0) {
                    console.log('The Progress Container Div "' + targetProgressContainer + ' could not be found!');
                    return;
                }

                $(targetProgressContainer).html($(_progressContainer).html());
            },
            statusCode:{
                403: function (data) {
                    window.top.location.href = sessionEndedUrl;
                }
            },
            success: function (responseData, status, xhr) {
                    successCallback(responseData);
            },
            error: function (request, textStatus, errorThrown) {
                errorCallback(request, textStatus, errorThrown);
            }
        });

这是我的 Startup.ConfigureAuth 方法:

app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

            // Enable the application to use a cookie to store information for the signed in user
            // and to use a cookie to temporarily store information about a user logging in with a third party login provider
            // Configure the sign in cookie
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    // Enables the application to validate the security stamp when the user logs in.
                    // This is a security feature which is used when you change a password or add an external login to your account.  
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                },

                SlidingExpiration =true,
                ExpireTimeSpan = TimeSpan.FromDays(30)
            });
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
            app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));

我添加了一些规则来确保用户 url 是完整的域

 <rules>
        <rule name="Add www prefix to example.com domain" stopProcessing="true">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTP_HOST}" pattern="^example\.com" />
          </conditions>
          <action type="Redirect" url="http://www.example.com/{R:1}" />
        </rule>
      </rules>

有人有什么想法吗?

【问题讨论】:

  • 身份验证会话即将到期,因为身份验证票已过期?
  • 嘿Hakunamatata,我在验证代码中添加了。真的不明白为什么它会过期。
  • 你的逻辑看起来不错。唯一的问题是默认会话超时为 20 分钟,因此如果 20 分钟内没有活动,您的会话将过期。在配置中增加这个值。如果没有要处理的请求,IIS 还将根据空闲超时值回收应用程序池。也增加这个值。
  • 它是如此零星,有一段时间我会很好地浏览网站,但突然间它把我踢了出去。其他时候我登录,甚至没有导航 2-3 页,它把我踢了出去。我真的很茫然。
  • 会不会是因为服务器配置不好?我们曾经在我们的工作场所有过类似的经历,我很确定这个问题只出现在一个开发服务器中。如果你有幸在另一台服务器上检查它,你至少可以减轻一些痛苦。

标签: javascript asp.net ajax session


【解决方案1】:

在您的一个 cmets 中,您提到问题是间歇性的 - 它在大多数情况下都可以正常工作,但有时用户会被“踢出”? 冒着问显而易见的风险 - 您是否使用“进程内”会话并在网络场上运行您的应用程序?

如果您的应用在负载均衡器后面运行并且它使用“进程内”会话,则会出现您描述的症状。在这种情况下,只要负载均衡器将请求定向到同一台服务器,用户就可以了。如果稍后负载均衡器决定将其中一个请求定向到另一台服务器,则用户的会话信息将在那里不可用,您的代码会将重定向发送到登录页面。

更新 1

我专注于会话部分,但问题似乎出在身份验证 cookie 上。在这种情况下,cookie 会使用您的 web.config 的 部分中指定的密钥进行加密/解密。如果网络场中不同服务器的这些设置不同,则无法在另一台服务器上解密在一台服务器上加密的身份验证 cookie,从而导致用户的“IsAuthenticated”属性为假。您的 web.config 中是否有如下所述的设置:msdn.microsoft.com/en-us/library/eb0zx8fc.aspx?

更新 2 - 如何将机器密钥添加到您的 web.config

按照下面 cmets 中的问题,这是将机器密钥添加到应用程序的最简单方法(基于 IIS7 的示例)。

  1. 转到您的本地 IIS 选择您的站点,然后在功能窗格中双击“Machine Key”图标。

如果您的应用程序没有在本地 IIS 中,您可以在“虚拟”站点上生成密钥,然后将配置部分复制到应用程序的 web.config。

  1. 点击“生成密钥”

  1. 检查网站的 web.config

  1. 您的密钥将如下例所示

您现在可以简单地将&lt;machineKey&gt; 复制到您的应用程序 web.config。

【讨论】:

  • 嘿 Rafal,是的,它是进程内的,并且托管在一个流行的 asp.net 托管服务提供商上,所以我认为它会在一个网络场上。我想虽然当会话丢失时,我可以使用用户身份验证 cookie (AspNet.ApplicationCookie) 重新加载会话,但这也会丢失。这是否意味着 AspNet.ApplicationCookie 也存储在服务器上的 session 中?
  • 所以也许是关于 web.config 中的 设置?我已经更新了我的答案。
  • 鉴于这是一个单一的应用程序,这是否适用于我
  • 是的。当您想在负载平衡环境中运行您的应用程序时,您应该将 设置添加到您的 web.config。如果您的配置中没有此设置,那么您将遇到间歇性问题,例如解密身份验证 cookie 的问题。如果你使用 ViewState,另一个会不时刹车的想法是 ViewState。 ViewState 也使用 部分中的密钥进行加密。对于 ViewState,您将收到异常“Invalid ViewState”,如下所述:support.microsoft.com/en-gb/kb/2915218
  • 我从我看到的帖子中通过 IIS 添加了机器密钥,选项:SHA 加密自动、验证密钥 -> 生成唯一密钥和解密密钥 -> 生成唯一密钥。我的网站出现故障,我收到此错误“指定的解密密钥包含无效的十六进制字符。”我看到它的键中有“isolateapps”。如果我删除它 IsolateApps 它可以工作。有什么区别。
【解决方案2】:

我们在我们的应用程序中遇到了类似的问题,也许这会对您有所帮助。身份验证令牌存储为 cookie,我们的应用程序也在 cookie 中存储了许多其他信息,其中一些 cookie 的名称是动态生成的。我们发现,不同的浏览器对它们为一个站点存储的 cookie 数量有限制,并且会丢弃最旧的未修改的 cookie。如果您有一段时间没有刷新您的身份验证 cookie,它最终会成为最旧的,并被丢弃。对我们来说,解决方案是将我们使用 cookie 的大部分地方移至本地存储,将我们的 cookie 列表保持在一个定义明确且有限的列表中。

【讨论】:

    猜你喜欢
    • 2021-03-03
    • 2019-07-18
    • 1970-01-01
    • 2011-03-31
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    • 1970-01-01
    相关资源
    最近更新 更多