.NET Core 6中会话过期时如何从任意控制器动作单点重定向至登录方法
.NET Core 6会话过期统一重定向到登录的实现方案
针对你需要在会话过期时从任意控制器动作统一重定向到登录页的需求,最简洁的做法是通过全局中间件或全局过滤器实现单点逻辑,避免在每个控制器重复代码。以下是两种可行方案:
方案一:自定义会话检测中间件(全局拦截所有请求)
中间件能拦截所有进入应用的请求,适合需要覆盖非控制器请求(如静态资源意外访问)的场景。
1. 配置会话与认证服务(Program.cs)
先在启动类中配置会话过期时间和Cookie认证:
var builder = WebApplication.CreateBuilder(args); // 添加控制器视图服务 builder.Services.AddControllersWithViews(); // 配置会话:设置过期时间、Cookie属性 builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(20); // 会话闲置20分钟后过期 options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); // 配置Cookie认证:指定登录路径、过期策略 builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Account/Login"; // 登录页路由 options.SlidingExpiration = true; // 用户活跃时自动延长有效期 options.ExpireTimeSpan = TimeSpan.FromMinutes(20); // 认证Cookie过期时间与会话保持一致 }); var app = builder.Build(); // 中间件顺序不可乱:HTTPS重定向 → 静态资源 → 路由 → 认证 → 授权 → 会话 → 自定义中间件 → 路由映射 app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); // 注册自定义会话过期中间件 app.UseSessionExpiration(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
2. 编写会话过期中间件
创建中间件类和扩展方法:
public class SessionExpirationMiddleware { private readonly RequestDelegate _next; public SessionExpirationMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { // 排除登录页和静态资源路径,避免循环重定向 var excludedPaths = new[] { "/Account/Login", "/lib", "/css", "/js" }; if (!excludedPaths.Any(path => context.Request.Path.StartsWithSegments(path))) { // 检查会话中存储的用户标识(根据你的实际存储字段调整,比如UserId) var userId = context.Session.GetString("UserId"); if (string.IsNullOrEmpty(userId)) { // 清除无效认证票据 await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); // 重定向到登录页,携带原路径以便登录后返回 var returnUrl = context.Request.Path + context.Request.QueryString; context.Response.Redirect($"/Account/Login?ReturnUrl={Uri.EscapeDataString(returnUrl)}"); return; } } // 会话有效,继续执行后续中间件 await _next(context); } } // 扩展方法用于注册中间件 public static class SessionExpirationMiddlewareExtensions { public static IApplicationBuilder UseSessionExpiration(this IApplicationBuilder builder) { return builder.UseMiddleware<SessionExpirationMiddleware>(); } }
方案二:全局动作过滤器(仅针对控制器动作)
如果只需要拦截控制器的动作方法,用全局过滤器更轻量:
1. 编写会话检查过滤器
public class SessionCheckFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { // 排除登录动作,避免循环重定向 var controller = context.RouteData.Values["controller"]?.ToString(); var action = context.RouteData.Values["action"]?.ToString(); if (controller != "Account" || action != "Login") { // 检查会话中的用户标识 var userId = context.HttpContext.Session.GetString("UserId"); if (string.IsNullOrEmpty(userId)) { // 重定向到登录页,携带原路径 var returnUrl = context.HttpContext.Request.Path + context.HttpContext.Request.QueryString; context.Result = new RedirectToActionResult( actionName: "Login", controllerName: "Account", routeValues: new { ReturnUrl = Uri.EscapeDataString(returnUrl) }); } } } public void OnActionExecuted(ActionExecutedContext context) { // 无需处理后续逻辑 } }
2. 注册全局过滤器(Program.cs)
在添加控制器服务时注册过滤器:
builder.Services.AddControllersWithViews(options => { options.Filters.Add<SessionCheckFilter>(); });
关键注意事项
- 会话与认证Cookie的过期时间要保持一致,避免出现会话过期但认证仍有效的矛盾情况。
- 必须排除登录页路径,防止重定向循环。
- 携带
ReturnUrl参数,让用户登录后能回到之前访问的页面,提升体验。
内容的提问来源于stack exchange,提问作者user22619879
相关产品推荐
相关产品推荐

