You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ASP.NET会话是否支持绝对过期?.NET 4.5.2/MVC5.2.3需求咨询

好问题!在你用的.NET 4.5.2 + ASP.NET MVC 5.2.3环境里,默认的Session确实只支持滑动过期——就是用户每操作一次,过期时间就自动往后延。但想要实现你说的「不管用户有没有操作,固定20分钟后强制销毁会话」的绝对过期效果,完全是可以做到的,给你几个实用的方案:

方案1:结合Forms身份验证的绝对过期(如果用了Forms Auth)

如果你的项目已经在用Forms身份验证,那可以直接利用它的绝对过期特性,把Session的生命周期和身份票据绑定在一起。登录时这么写:

// 生成绝对过期的身份票据
var authTicket = new FormsAuthenticationTicket(
    version: 1,
    name: username,
    issueDate: DateTime.Now,
    expiration: DateTime.Now.AddMinutes(20), // 固定20分钟后过期
    isPersistent: false,
    userData: string.Empty,
    cookiePath: FormsAuthentication.FormsCookiePath
);

// 加密并写入Cookie
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(authCookie);

// 同时初始化Session
Session["SomeKey"] = "SomeValue";

然后在Global.asaxSession_Start或者自定义授权过滤器里,检查票据是否过期,过期就销毁Session:

protected void Session_Start(object sender, EventArgs e)
{
    if (User.Identity is FormsIdentity formsIdentity && !formsIdentity.Ticket.Expired)
    {
        // 票据有效,正常处理
    }
    else
    {
        // 票据过期,销毁Session并跳转到登录页
        Session.Abandon();
        FormsAuthentication.SignOut();
        Response.Redirect("~/Account/Login");
    }
}
方案2:手动记录Session创建时间,全局检查

如果没用到Forms Auth,或者想单独控制Session的绝对过期,可以自己在Session创建时记好开始时间,然后在每个请求过来时检查是否超时:

  1. 先在Global.asax里记录Session的创建时间:
protected void Session_Start(object sender, EventArgs e)
{
    // 记录Session创建时间和绝对过期时长
    Session["SessionCreatedAt"] = DateTime.Now;
    Session["AbsoluteExpiryMinutes"] = 20;
}
  1. 写一个MVC的Action过滤器,用来在每个请求前做检查:
public class AbsoluteSessionExpiryFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var session = filterContext.HttpContext.Session;
        if (session == null) return;

        var createdAt = session["SessionCreatedAt"] as DateTime?;
        var expiryMinutes = session["AbsoluteExpiryMinutes"] as int?;

        if (createdAt.HasValue && expiryMinutes.HasValue)
        {
            if (DateTime.Now > createdAt.Value.AddMinutes(expiryMinutes.Value))
            {
                // 已到绝对过期时间,销毁Session
                session.Abandon();
                // 顺便清除Session Cookie,避免残留
                if (filterContext.HttpContext.Request.Cookies["ASP.NET_SessionId"] != null)
                {
                    var sessionCookie = new HttpCookie("ASP.NET_SessionId")
                    {
                        Expires = DateTime.Now.AddDays(-1),
                        Path = filterContext.HttpContext.Request.ApplicationPath
                    };
                    filterContext.HttpContext.Response.Cookies.Add(sessionCookie);
                }
                // 跳转到登录页
                filterContext.Result = new RedirectResult("~/Account/Login");
            }
        }
        base.OnActionExecuting(filterContext);
    }
}
  1. 把这个过滤器注册到全局(在FilterConfig.cs里):
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new AbsoluteSessionExpiryFilter());
    // 其他全局过滤器...
}
方案3:自定义Session存储提供器(进阶)

如果需要更底层的控制,比如在分布式场景下做绝对过期,可以自定义Session存储提供器,在存储Session数据时同时记录绝对过期时间,每次读取时自动检查是否过期。不过这个方案相对复杂,一般前两种就足够满足你的需求了。

小提示
  • 不用特意去禁用默认的滑动过期,因为我们的检查逻辑会优先判断绝对过期时间——哪怕滑动过期还没到,只要绝对时间到了就会销毁Session。
  • 调用Session.Abandon()后,记得清除客户端的ASP.NET_SessionId Cookie,不然用户可能还带着旧Cookie访问,导致创建新的Session。

内容的提问来源于stack exchange,提问作者ptf

火山引擎 最新活动