不断松散会话状态ASP.NET

时间:2016-06-19 22:09:16

标签: javascript asp.net ajax session

我的网站不断失去其会话状态并开除用户,但我无法弄清楚原因。

我有一个动作过滤器,试图检查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));

我添加了一些规则以确保用户网址是完整的域

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

有没有人有任何想法?

2 个答案:

答案 0 :(得分:2)

在你的一条评论中,你提到这个问题是间歇性的 - 大部分时间都可以正常工作,但有时用户会被“踢出”? 有明显要求的风险 - 您是否使用“进程内”会话并在Web场上运行您的应用程序?

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

更新1

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

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

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

  1. 转到您当地的IIS选择您的站点,然后在fetures窗格中双击“Machine Key”图标。
  2. enter image description here

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

    1. 点击“生成密钥”
    2. enter image description here

      1. 检查网站的web.config
      2. enter image description here

        1. 您的密钥将如下所示
        2. enter image description here

          现在,您只需将<machineKey>复制到您的应用程序web.config。

          即可

答案 1 :(得分:0)

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