这里有几个单独的问题:服务器会话超时,客户端对服务器会话超时的感知,以及对用户不活动的处理。
1) 您如何在服务器端实现会话超时?
2)由于您通过心跳(每 5 秒)保持会话处于活动状态,因此您可能永远不会在服务器上达到会话超时。
您只能在客户端进行管理,方法是在达到超时值后使用 JavaScript 进行注销调用。使用 window.setTimeout() 在客户端设置不活动超时。当计时器触发时,将浏览器重定向到注销控制器或 sessionExpired 控制器(您的选择)。使用 beforeUnload 事件清除计时器,并在页面加载时设置一个新计时器。
然后,让服务器超时值来处理用户关闭浏览器和心跳停止的情况。
摘自 web.config 将我的会话超时定义为 20 分钟:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="20" slidingExpiration="true" protection="All" name="ilApp" requireSSL="false" defaultUrl="~/Account/Login" />
</authentication>
<sessionState timeout="20" />
以及我添加到 /Shared/_Layout.cshtml 的 javascript 代码,因为该文件包含在我网站上的每个页面中:
@* Redirect browser to session expiration page on timeout *@
@{
var authenticationSettings = System.Configuration.ConfigurationManager.GetSection("system.web/authentication") as System.Web.Configuration.AuthenticationSection;
}
<script type="text/javascript">
$(document).ready(function () {
function ilSessionTimeout() {
window.location = '@Url.Action("SessionExpired", "Account", new { area = "" })';
};
function ilSessionTimeoutWarning() {
$.jGrowl('You will be logged off soon due to inactivity.', { sticky: true, theme: 'growl-warning', header: 'Attention' });
};
// remember our timers so we can cancel when we unload this page and reset them on the next page load
var g_pageTimer = window.setTimeout(ilSessionTimeout, @authenticationSettings.Forms.Timeout.TotalMilliseconds);
var g_pageTimerWarning = window.setTimeout(ilSessionTimeoutWarning, Math.round(@authenticationSettings.Forms.Timeout.TotalMilliseconds*0.8));
// clean up anything that needs cleaning before we leave this page
window.onbeforeunload = function(e) {
// clear the timers
window.clearTimeout(g_pageTimer);
window.clearTimeout(g_pageTimerWarning);
};
});
</script>
这会设置两个计时器,一个用于会话超时期限(基于 web.config 中定义的值),另一个用于 80% 到期时使用 jGrowl 显示警告消息。我在 javascript 全局变量 (g_pageTimer*) 中为 unload 事件保留了两个计时器的句柄。
我连接到 window.onbeforeunload 以确保在页面即将更改时取消计时器。没有这个,无论客户端活动如何,超时都是绝对重定向到注销。
当超时计时器触发时,我会重定向到我网站上的一个页面 /Account/SessionExpired,该页面会向用户显示一条消息,然后完成注销。在我的示例中,我使用的是 ASP.Net Identity 2,但无论您在注销期间通常做什么,都可以在此处执行。
//
// GET: /Account/SessionExpired
[AllowAnonymous]
public ActionResult SessionExpired()
{
try
{
System.Web.HttpContext.Current.Session.RemoveAll(); // Remove all session variables that we used
AuthenticationManager.SignOut();
}
catch
{
// do nothing
}
return View();
}