You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 6会话超时服务器不生效及过期跳转登录页问题

ASP.NET Core 6会话超时配置问题及解决方案

问题描述

我正在调整ASP.NET Core 6项目,将会话超时设置为50分钟(微软文档显示默认超时为20分钟)。本地测试时,会话50分钟过期后会跳转至应用错误页,但部署到服务器后,会话仍在默认20分钟时过期。请问如何实现50分钟会话超时,并在会话过期后刷新页面时跳转至登录页而非错误页?

我的代码

Program.cs

using OtherSportsMaster;

namespace OtherSportsMaster
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel(options =>
                {
                    options.Limits.MaxRequestBodySize = null;
                })
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .UseUrls("http://localhost:5001")
                .Build();

            host.Run();
            //CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

Startup.cs

using OtherSportsMaster.Data;
using OtherSportsMaster.Models;
using OtherSportsMaster.Models.MasterDAL;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Server.IIS;
using System.Data.Common;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Authorization;

namespace OtherSportsMaster
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
            //BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

        public IConfiguration Configuration { get; }

        // 运行时调用此方法向容器添加服务
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(IISServerDefaults.AuthenticationScheme);    
            services.AddHttpContextAccessor();
            services.AddDistributedMemoryCache();

            // 设置会话超时,默认20分钟
            services.AddSession(options =>
            {
                //options.Cookie.Name = ".AspNetCore.Session";
                options.IdleTimeout = TimeSpan.FromMinutes(50);
                options.Cookie.HttpOnly = true;
                options.Cookie.IsEssential = true;
            });
            //.AddDistributedMemoryCache();

            services.AddControllersWithViews();
            //services.AddRazorPages();

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped<CommanCls>();
            services.AddScoped<DBConnectionCls>();
            services.AddMvc(option => option.EnableEndpointRouting = false);

            services.Configure<IISServerOptions>(options =>
            {
                options.MaxRequestBodySize = int.MaxValue;
            });
            //services.Configure<FormOptions>(x =>
            //{
            //    x.ValueLengthLimit = int.MaxValue;
            //    x.MultipartBodyLengthLimit = int.MaxValue;
            //    x.MultipartHeadersLengthLimit = int.MaxValue;

            //    x.ValueCountLimit = 10;
            //    x.MemoryBufferThreshold = Int32.MaxValue;
            //});
            //services.AddMvc();
            //services.AddMvc(options =>
            //{
            //    options.Filters.Add(typeof(AuthorizeAttribute));
            //    options.MaxModelBindingCollectionSize = int.MaxValue;
            //});
        }

        // 运行时调用此方法配置HTTP请求管道
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                //app.UseHsts();
            }
            //app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseSession();
            app.UseMvc();
            AppHttpContext.Services = app.ApplicationServices;

            //app.Use(async (context, next) =>
            //{
            //    context.Features.Get<IHttpMaxRequestBodySizeFeature>().MaxRequestBodySize = null; // unlimited I guess
            //    await next.Invoke();
            //});

            //app.UseEndpoints(endpoints =>
            //{
            //    endpoints.MapControllerRoute(
            //        name: "default",      
            //        pattern: "{controller=Login}/{action=Index}/{id?}");
            //});
            //app.UseMvc(ConfigureRoute);
            // app.UseMvcWithDefaultRoute();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Master}/{action=Login}/{id?}");
            });

            //app.Run(async (context) =>
            //{
            //    await context.Response.WriteAsync("\"No ");
            //});
        }
    }
}

web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <location path="." inheritInChildApplications="false">
        <system.web>
            <httpRuntime maxRequestLength="1048576" />
        </system.web>
        <system.webServer>
            <security>
                <requestFiltering>
                    <requestLimits maxUrl="65536" maxQueryString="2097151" maxAllowedContentLength="4294967295" />
                    <!-- 1 GB-->                                                    <!-- ~ 4GB -->
                </requestFiltering>
            </security>
            <handlers>
                <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
            </handlers>
            <aspNetCore requestTimeout="00:50:00" processPath=".\OtherSportsMaster.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
        </system.webServer>
        <system.web.extensions>
            <scripting>
                <webServices>
                    <jsonSerialization maxJsonLength="86753090"/>
                </webServices>
            </scripting>
        </system.web.extensions>
    </location>
</configuration>
<!--ProjectGuid: ac80560e-7b73-4211-994b-881b5818045d-->

解决方案

一、解决服务器端会话20分钟过期问题

服务器上会话提前过期的核心原因是IIS应用池闲置超时回收,默认应用池闲置20分钟会自动回收进程,导致内存中的Session数据丢失。

  1. 调整IIS应用池闲置超时

    • 打开IIS管理器,找到对应应用的应用池
    • 右键选择“高级设置”
    • 找到“闲置超时(分钟)”,设置为大于50分钟(比如55分钟),或者设为0表示永不回收(生产环境需根据实际运维情况调整)
  2. 完善Session配置
    在Startup.cs的ConfigureServices方法中,给Session Cookie添加过期时间,确保和IdleTimeout一致:

    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromMinutes(50);
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
        options.Cookie.Expires = TimeSpan.FromMinutes(50); // 新增此行,同步Cookie过期时间
    });
    
  3. 确认中间件顺序
    当前Configure方法中app.UseSession()在app.UseMvc()之前,这个顺序是正确的,不要调整,确保Session中间件先于MVC执行。

二、实现会话过期跳转登录页而非错误页

通过自定义全局过滤器来检查会话状态,避免跳转到错误页:

  1. 创建会话检查过滤器
    在项目中新增一个类:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    namespace OtherSportsMaster
    {
        public class SessionCheckFilter : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext context)
            {
                // 替换为你实际判断用户登录状态的Session键
                var userInfo = context.HttpContext.Session.GetString("UserInfo");
                if (string.IsNullOrEmpty(userInfo))
                {
                    // 排除登录页面,防止循环跳转
                    var controller = context.RouteData.Values["controller"]?.ToString() ?? "";
                    var action = context.RouteData.Values["action"]?.ToString() ?? "";
                    if (!controller.Equals("Master", StringComparison.OrdinalIgnoreCase) 
                        || !action.Equals("Login", StringComparison.OrdinalIgnoreCase))
                    {
                        // 跳转到登录页
                        context.Result = new RedirectToRouteResult(new RouteValueDictionary
                        {
                            { "controller", "Master" },
                            { "action", "Login" }
                        });
                    }
                }
                base.OnActionExecuting(context);
            }
        }
    }
    
  2. 注册全局过滤器
    在Startup.cs的ConfigureServices方法中,修改AddMvc的配置,添加过滤器:

    services.AddMvc(option => 
    {
        option.EnableEndpointRouting = false;
        option.Filters.Add(typeof(SessionCheckFilter)); // 注册会话检查过滤器
    });
    
  3. 调整错误页逻辑
    非开发环境下的app.UseExceptionHandler("/Home/Error")仅处理系统异常,会话过期的情况已经由过滤器处理,不会再触发错误页跳转。

注意事项

  • 如果服务器部署了多实例应用,建议使用分布式缓存(如Redis)替代DistributedMemoryCache,避免Session数据无法共享。
  • 确保服务器上的.NET Core运行时版本和项目目标版本一致。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 09:36:03