ASP.NET推送重定向会话超时

时间:2009-01-27 19:56:22

标签: asp.net redirect session-timeout server-push

我正在寻找一个教程,博客条目,或者在会话到期时自动推送用户(即没有回发)的网站背后的技术的一些帮助。任何帮助表示赞赏

10 个答案:

答案 0 :(得分:27)

通常,您设置会话超时,并且您还可以添加页眉以自动将当前页面重定向到您在会话超时之前清除会话的页面。

来自http://aspalliance.com/1621_Implementing_a_Session_Timeout_Page_in_ASPNET.2

namespace SessionExpirePage
{
    public partial class Secure : System.Web.UI.MasterPage
    {
        public int SessionLengthMinutes
        {
            get { return Session.Timeout; }
        }
        public string SessionExpireDestinationUrl
        {
            get { return "/SessionExpired.aspx"; }
        }
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            this.PageHead.Controls.Add(new LiteralControl(
                String.Format("<meta http-equiv='refresh' content='{0};url={1}'>", 
                SessionLengthMinutes*60, SessionExpireDestinationUrl)));
        }
    }
}

SessionExpireDestinationUrl应链接到清除会话和任何其他用户数据的页面。

当刷新标头过期时,它会自动将它们重定向到该页面。

答案 1 :(得分:10)

您无法真正从您的网站“推送”客户端。您的网站将响应客户的请求,但事实确实如此。

这意味着您需要编写一些客户端(Javascript)来确定用户何时超时,可能是通过将当前时间与他们在站点cookie中更新的时间进行比较(您更新了)每当用户访问您网站上的网页时显示当前时间,然后在差异大于特定金额时重定向。

(我注意到有些人主张只创建一个脚本,在一定时间后在页面上转发用户。这可以在简单的情况下工作,但如果用户在网站上打开了两个窗口,并且正在使用一个窗口,而另一个窗口不那么多,不那么多的窗口会突然将用户重定向到转发页面,即使用户经常访问该网站。此外,它不是与任何保持你在服务器端进行的会话实际上是同步的。另一方面,编码肯定更容易,如果这足够好,那就太好了!)

答案 2 :(得分:6)

在&lt; HEAD&gt;中部分,使用这样的META刷新标记:

<meta http-equiv="refresh" content="0000; URL=target_page.html">

其中0000是您的会话超时(以秒为单位),target_page.html是要重定向到的网页的地址。

答案 3 :(得分:3)

使用自定义页面类和Javascript我们也可以实现它。

创建自定义页面基类并将常用功能代码写入此类。通过这个类,我们可以将共同的功能分享给其他网页。在这个类中,我们需要继承 System.Web.UI.Page 类。将以下代码放入Pagebase类

<强> PageBase.cs

namespace AutoRedirect
{
    public class PageBase : System.Web.UI.Page
    {
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            AutoRedirect();
        }

        public void AutoRedirect()
        {
            int int_MilliSecondsTimeOut = (this.Session.Timeout * 60000);
            string str_Script = @"
               <script type='text/javascript'> 
                   intervalset = window.setInterval('Redirect()'," +
                       int_MilliSecondsTimeOut.ToString() + @");
                   function Redirect()
                   {
                       window.location.href='/login.aspx'; 
                   }
               </script>";

           ClientScript.RegisterClientScriptBlock(this.GetType(), "Redirect", str_Script);
        }
    }
}

以上 AutoRedirect功能将用于在会话到期时重定向登录页面,使用 javascript window.setInterval ,此window.setInterval以特定方式重复执行javascript函数时间延迟。这里我们将时间延迟配置为会话超时值。一旦达到会话到期时间,则自动执行重定向功能并控制转移到登录页面。

<强> OriginalPage.aspx.cs

namespace appStore
{
    public partial class OriginalPage: Basepage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }     
    }
}

<强> OriginalPage.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="OriginalPage.aspx.cs" Inherits="AutoRedirect.OriginalPage" %>

<强> 的Web.config

<system.web>    
    <sessionState mode="InProc" timeout="3"></sessionState>
</system.web>

注意: 使用Javascript的优点是你可以在location.href之前的警告框中显示自定义消息,这对用户来说非常有意义。 如果您不想使用Javascript,也可以选择元重定向

public void AutoRedirect()
{
    this.Header.Controls.Add(new LiteralControl(
        String.Format("<meta http-equiv='refresh' content='{0};url={1}'>",
            this.Session.Timeout * 60, "login.aspx")));
}

答案 4 :(得分:2)

只需将此代码段复制并粘贴到Web.Config文件中即可:

<authentication mode="Forms">
  <forms loginUrl="~/Login.aspx" slidingExpiration="true" timeout="29" />
</authentication>

<sessionState timeout="30" mode="InProc" cookieless="false" />

您可以将此行添加到您的Site.Master:

Response.AppendHeader("Refresh", 
                      Convert.ToString((Session.Timeout * 60)) + 
                      ";URL=~/Login.aspx");

答案 5 :(得分:2)

我正在使用MVC3 ASp.net作为初学者,我尝试了很多解决方案来解决我的会话问题(因为我在我的代码中使用了Session变量,并且在超时后我没有会话值而我保持使用它我只是发现我的问题出在配置文件中。认证和sessionState之间的超时应该非常接近。所以他们同时杀死(空)//添加超时1和2进行测试..它应该在至少29和30                           

我也用其他方式工作:

从:

开始
    protected void Session_Start(object src, EventArgs e)
    {
        if (Context.Session != null)
        {
            if (Context.Session.IsNewSession)//|| Context.Session.Count==0)
            {
                string sCookieHeader = Request.Headers["Cookie"];
                if ((null != sCookieHeader) && (sCookieHeader.IndexOf("ASP.NET_SessionId") >= 0))
                {
                    //if (Request.IsAuthenticated)
                     FormsAuthentication.SignOut();
                     Response.Redirect("/Account/LogOn");
                }
            }
        }

    }

    protected void Session_End(object sender, EventArgs e)
    {
     //Code that runs when a session ends. 
     //Note: The Session_End event is raised only when the sessionstate mode 
     //is set to InProc in the Web.config file. If session mode is set to StateServer
      //or SQLServer, the event is not raised. 
        Session.Clear();          
    }

并且:

public class SessionExpireFilterAttribute : ActionFilterAttribute
{

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpContext ctx = HttpContext.Current;

        // check if session is supported
        if (ctx.Session != null)
        {

            // check if a new session id was generated
            if (ctx.Session.IsNewSession)
            {
                // If it says it is a new session, but an existing cookie exists, then it must
                // have timed out
                string sessionCookie = ctx.Request.Headers["Cookie"];
                if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0))
                {
                    ctx.Response.Redirect("~/Home/LogOn");
                }
            }
        }

        base.OnActionExecuting(filterContext);
    }
}

甚至与Ajax合作解决会话问题:

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (Session.Count == 0 || Session["CouncilID"] == null)
            Response.Redirect("/Account/LogOn");

        if (Request.IsAjaxRequest() && (!Request.IsAuthenticated || User == null))
        {
            filterContext.RequestContext.HttpContext.Response.StatusCode = 401;
        }
        else
        {
            base.OnActionExecuting(filterContext);
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class AuthorizeUserAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            if (!httpContext.Request.IsAjaxRequest())
            {//validate http request.
                if (!httpContext.Request.IsAuthenticated
                    || httpContext.Session["User"] == null)
                {
                    FormsAuthentication.SignOut();
                    httpContext.Response.Redirect("~/?returnurl=" + httpContext.Request.Url.ToString());
                    return false;
                }
            }
            return true;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.Result = new JsonResult
                {
                    Data = new
                    {
                        // put whatever data you want which will be sent
                        // to the client
                        message = "sorry, but you were logged out"
                    },
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };
            }
            else
            {
                base.HandleUnauthorizedRequest(filterContext);
            }
        }

    }

答案 6 :(得分:1)

不幸的是,它无法完成。会话超时仅发生在服务器端,在用户执行某种回发操作之前,您不会检测到此事。

但是,您可以做的是注入一些HTML或JavaScript标头代码,这些代码会在与会话超时相同的时间范围内自动将用户推送到注销页面。这并不能保证完美的同步,如果您的用户正在做一些耗时的项目并且您没有重置时钟,则可能会遇到问题。

我通常会将此代码添加到我的Page_Load事件中以实现此目的。

' Register Javascript timeout event to redirect to the login page after inactivity
  Page.ClientScript.RegisterStartupScript(Me.GetType, "TimeoutScript", _
                                              "setTimeout(""top.location.href = 'Login.aspx'""," & _
                                               ConfigurationManager.AppSettings("SessionTimeoutMilliseconds") & ");", True)

答案 7 :(得分:1)

当然,你需要在控制器类上使用[Authorize],甚至在特定的情况下使用Action。

[Authorize]
public class MailController : Controller
{
}

答案 8 :(得分:1)

如果您使用以下登录控制器,它将在登录前将您发送到请求的URL:

   [HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    {

        if (ModelState.IsValid)
        {
            if (Membership.ValidateUser(model.UserName, model.Password))
            {

                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);

                if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                    && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                {
                    //return Redirect(returnUrl);
                    if (!String.IsNullOrEmpty(returnUrl))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                      return RedirectToAction("Index", "Home");
                    }

                }
                else
                {
                    return RedirectToAction("Index", "Home");
                }
            }
            else
            {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

答案 9 :(得分:0)

正如Zhaph-Ben Duguid指出的那样,对于AJAX请求来说这很棘手。这是我的解决方案,使用AJAX(使用Telerik Web控件,但我们使用ASP.NET AJAX工具包,我相信)。

简而言之,我推出了自己的滑动到期会话类型。

在我的Site.Master中,我正在更新每个回发的会话变量(回发或AJAX请求,因为AJAX请求仍然启动Page_Load事件):

protected void Page_Load(object sender, EventArgs e)
    {
        if (!this.IsPostBack)
        {
            if (this.Request.IsAuthenticated)
                this.pnlSessionKeepAlive.Visible = true;
            else
                this.pnlSessionKeepAlive.Visible = false;
        }

        if (this.Session["SessionStartDateTime"] != null)
            this.Session["SessionStartDateTime"] = DateTime.Now;
        else
            this.Session.Add("SessionStartDateTime", DateTime.Now);
    }

然后在我的site.master标记中,我在一个ASPX页面中包含一个iframe,我使用“幕后”检查我的自定义滑动过期是否已过期:

<asp:Panel runat="server" ID="pnlSessionKeepAlive" Visible="false">
 <iframe id="frame1" runat="server" src="../SessionExpire.aspx" frameborder="0" width="0" height="0" / >
 </asp:Panel>

现在在我的SessionExpire.aspx页面中,我只是经常刷新页面并检查时间戳是否已经失效,如果是,我会重定向到我的logout.aspx页面,然后确定将用户发送回的登录页面:

public partial class SessionExpire : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        /* We have to do all of this because we need to redirect to 2 different login pages. The default .NET
         * implementation does not allow us to specify which page to redirect expired sessions, its a fixed value.
         */
        if (this.Session["SessionStartDateTime"] != null)
        {
            DateTime StartTime = new DateTime();
            bool IsValid = DateTime.TryParse(this.Session["SessionStartDateTime"].ToString(), out StartTime);
            if (IsValid)
            {
                int MaxSessionTimeout = Convert.ToInt32(ConfigurationManager.AppSettings["SessionKeepAliveMins"]);
                IsValid = (DateTime.Now.Subtract(StartTime).TotalMinutes < MaxSessionTimeout);
            }

            // either their session expired or their sliding session timeout has expired. Now log them out and redirect to the correct
            // login page.
            if (!IsValid)
                this.Logout();
        }
        else
            this.Logout();

        // check every 60 seconds to see if the session has expired yet.
        Response.AddHeader("Refresh", Convert.ToString(60));
    }

    private void Logout()
    {
        this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "TimeoutScript",
                    "setTimeout(\"top.location.href = '../Public/Logout.aspx'\",\"1000\");", true);
    }
}

非常感谢上面发布信息的人们,这引导我找到我的解决方案并希望能帮助他人。