我正在寻找有关会话过期时自动推送用户(即无需后台提交)的网站技术的教程、博客文章或帮助。感谢任何帮助。
我正在寻找有关会话过期时自动推送用户(即无需后台提交)的网站技术的教程、博客文章或帮助。感谢任何帮助。
来自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应该链接到一个页面,在这个页面上你可以清除session和任何其他用户数据。
当刷新头过期时,它会自动将用户重定向到那个页面。
你无法通过网站直接“推送”客户端。你的网站可以响应来自客户端的请求,但仅限于此。
这意味着你需要编写一些客户端脚本(JavaScript),用于判断用户何时超时,可能是通过将当前时间与他们在站点cookie中最近的时间进行比较(每次用户访问站点页面时更新该时间),然后在差异大于一定量时进行重定向。
(我注意到有些人建议只需创建一个脚本,在页面上停留一定时间后即可转发用户。这在简单情况下可以工作,但如果用户在站点上开了两个窗口,并且一个窗口使用非常频繁,而另一个窗口则不是很频繁,那么不是很频繁的窗口将突然将用户重定向到转发页面,尽管用户已经一直在该站点上。此外,它与服务器端保持同步的任何会话保持都不是真正同步的。另一方面,它肯定更容易编写,如果这足够好,那就太棒了!)
<meta http-equiv="refresh" content="0000; URL=target_page.html">
在这里,0000代表您的会话超时时间(以秒为单位),而target_page.html则是要重定向到的页面的地址。
创建一个自定义的PageBase类,并将常用功能代码写入该类中。通过此类,我们可以将常用函数共享给其他网页。在此类中,我们需要继承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 function 将会在会话过期时重定向到登录页面,使用了 javascript window.setInterval。这个 window.setInterval 函数会按照指定的时间间隔重复执行一个 JavaScript 函数。在这里我们将时间间隔配置为会话超时时间。一旦达到会话过期时间,就会自动执行 Redirect 函数并控制转移到登录页面。
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>
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")));
}
只需将以下代码片段复制并粘贴到您的Web.Config文件中:
<authentication mode="Forms">
<forms loginUrl="~/Login.aspx" slidingExpiration="true" timeout="29" />
</authentication>
<sessionState timeout="30" mode="InProc" cookieless="false" />
Response.AppendHeader("Refresh",
Convert.ToString((Session.Timeout * 60)) +
";URL=~/Login.aspx");
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);
}
}
}
当然,您需要在控制器类或特定操作中使用[Authorize]
。
[Authorize]
public class MailController : Controller
{
}
如果您使用以下的登录控制器,它将在登录之前将您发送到请求的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);
}
很遗憾,这是做不到的。会话超时只发生在服务器端,直到用户执行某种后台操作才能检测到。
然而,您可以注入一些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)
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标记中,我包含了一个iframe,其中包含一个ASPX页面,我在“幕后”使用它来检查并查看我的自定义滑动过期是否已过期:
<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);
}
}
非常感谢上面发布信息的人,这让我找到了解决方案,希望能帮助其他人。