我正在寻找有关在会话到期时自动推送用户(即没有回发)的网站背后的技术的教程、博客条目或一些帮助。任何帮助表示赞赏
10 回答
通常,您设置会话超时,并且您可以另外添加页眉以自动将当前页面重定向到您在会话超时之前清除会话的页面。
来自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 应该链接到您清除会话和任何其他用户数据的页面。
当刷新标头过期时,它会自动将它们重定向到该页面。
您不能真正从您的网站“推送”客户。您的站点将响应来自客户的请求,但事实就是如此。
这意味着您需要编写一些客户端(Javascript)来确定用户何时超时,可能通过将当前时间与他们在站点 cookie 中的最近时间(您使用当前更新每次用户访问您网站上的页面的时间),然后如果差异大于一定数量则重定向。
(我注意到有些人提倡创建一个脚本,该脚本将在页面上经过一定时间后转发用户。这适用于简单的情况,但如果用户在网站上打开了两个窗口,并且正在使用一个窗口很多,另一个窗口不那么多,不那么多的窗口会突然将用户重定向到转发页面,即使用户一直在网站上。此外,它并不真正同步保持你在服务器端进行的任何会话。另一方面,编码肯定更容易,如果这足够好,那就太好了!)
在 <HEAD> 部分中,使用如下 META 刷新标签:
<meta http-equiv="refresh" content="0000; URL=target_page.html">
其中 0000 是以秒为单位的会话超时,而 target_page.html 是要重定向到的页面的地址。
使用自定义页面类和 Javascript 我们也可以实现它。
创建一个自定义的 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 函数将用于在会话到期时重定向登录页面,通过使用javascript window.setInterval,这个 window.setInterval 以特定的时间延迟重复执行一个 javascript 函数。在这里,我们将时间延迟配置为会话超时值。一旦达到会话到期时间,就会自动执行重定向功能并将控制转移到登录页面。
原始页面.aspx.cs
namespace appStore
{
public partial class OriginalPage: Basepage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
}
原始页面.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="OriginalPage.aspx.cs" Inherits="AutoRedirect.OriginalPage" %>
网页配置
<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")));
}
只需将此代码段复制并粘贴到您的 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");
我正在使用 MVC3 ASp.net 作为初学者,我尝试了许多解决方案来解决我的会话问题(因为我在我的代码中使用 Session 变量,并且在超时后我没有会话值而我继续使用它并且我只是发现我的问题出在配置文件中。Authentication 和 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);
}
}
}
不幸的是,它无法完成。会话超时仅发生在服务器端,在用户执行某种回发操作之前,您不会检测到这一点。
但是,您可以做的是注入一些 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)
当然,您需要[Authorize]
在特定的控制器类甚至 Action 上使用。
[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);
}
正如 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);
}
}
非常感谢上面发布信息的人,这使我找到了我的解决方案,并希望它对其他人有所帮助。