.NET Core 2.1升级3.1遇OptionsValidationException报错求助
问题概述
将ASP.NET Core 2.1应用升级至3.1后,首次加载项目时触发OptionsValidationException: Cookie.Expiration is ignored, use ExpireTimeSpan instead错误,场景为未登录用户访问默认路由的UserProfiles控制器,被重定向到登录页时触发异常。
原因分析
- API弃用:ASP.NET Core 3.0及以上版本中,
CookieAuthenticationOptions.Cookie.Expiration属性已被官方弃用,框架要求使用ExpireTimeSpan属性配置Cookie过期时间,继续使用旧属性会触发验证异常。 - 配置冲突:代码中同时通过
AddCookie和ConfigureApplicationCookie配置Cookie过期时间,导致配置优先级冲突,加重异常触发概率。 - 中间件顺序错误:会话中间件(
UseSession)的位置在认证中间件(UseAuthentication)之后,违反ASP.NET Core中间件执行顺序规范,加剧认证流程中的异常。 - 控制器未做登录校验:UserProfiles控制器的Index方法未先验证用户是否登录,直接尝试解析
User.Identity.Name,未登录时会引发额外异常。
解决方案
1. 替换弃用的Cookie过期配置
移除AddCookie中的options.Cookie.Expiration配置,改用options.ExpireTimeSpan统一设置Cookie过期时间。
2. 统一Cookie配置优先级
删除重复的ConfigureApplicationCookie配置(或保持与AddCookie配置一致),避免配置冲突。
3. 调整中间件执行顺序
按照ASP.NET Core官方规范调整中间件顺序,确保UseSession在UseAuthentication之前执行,同时添加必要的UseAuthorization中间件。
4. 完善控制器登录校验逻辑
在控制器方法开头先验证用户是否已登录,避免未登录时解析无效的User.Identity.Name。
修改后代码示例
Startup.cs ConfigureServices 方法修改
public void ConfigureServices(IServiceCollection services) { var connection = Configuration.GetConnectionString("DentalDBconnection"); services.AddDbContext<HoshmandDBContext>(option => option.UseSqlServer(connection)); services.AddAuthentication(option => { option.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; option.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie(options => { options.LoginPath = "/Logins/UserLogin/"; options.AccessDeniedPath = "/AccessDenied"; // 替换弃用的Cookie.Expiration,改用ExpireTimeSpan options.ExpireTimeSpan = TimeSpan.FromHours(10); }); services.AddDistributedMemoryCache(); services.AddSession(options => { options.IdleTimeout = TimeSpan.FromHours(2); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); // 移除重复的ConfigureApplicationCookie配置,避免冲突 // services.ConfigureApplicationCookie(option => // { // option.ExpireTimeSpan = TimeSpan.FromMinutes(540); // }); services.AddAuthorization(options => { options.AddPolicy("HasAccess", policy => policy.AddRequirements(new HasAccessRequirment())); }); services.AddTransient<IAuthorizationHandler, HasAccessHandler>(); services.AddTransient<IMvcControllerDiscovery, MvcControllerDiscovery>(); services.AddMvc(); }
Startup.cs Configure 方法修改
public void Configure(IApplicationBuilder app) { if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } var cachePeriod = Environment.IsDevelopment() ? "600" : "604800"; app.UseStaticFiles(new StaticFileOptions { OnPrepareResponse = ctx => { ctx.Context.Response.Headers.Append("Cache-Control", $"public, max-age={cachePeriod}"); } }); app.UseHttpsRedirection(); // 移除重复的UseStaticFiles调用 // app.UseStaticFiles(); app.UseCookiePolicy(); app.UseSession(); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); // 添加必要的授权中间件 app.UseEndpoints(endpoints => { endpoints.MapControllerRoute(name: "default", pattern: "{controller=UserProfiles}/{action=Index}/{id?}"); }); }
UserProfilesController.cs Index 方法修改
public async Task<IActionResult> Index(bool? passIsChanged = null) { if (passIsChanged != null) { ViewBag.isSuccessed = passIsChanged; } // 先验证用户是否已登录 if (!User.Identity.IsAuthenticated) { return RedirectToAction("UserLogin", "Logins"); } // 安全解析用户ID if (!int.TryParse(User.Identity.Name, out int id)) { return RedirectToAction("UserLogin", "Logins"); } var user = _context.UserAccountTbs.FirstOrDefault(a => a.UserId == id); if (user == null) { return RedirectToAction("UserLogin", "Logins"); } // 返回视图(原代码缺失,需补充) return View(user); }
验证步骤
- 启动应用,访问默认路由
- 未登录状态下会自动重定向到登录页,此时不再触发
OptionsValidationException - 登录后正常访问UserProfiles控制器的Index页面
内容的提问来源于stack exchange,提问作者Hedayat Hoshmand
相关产品推荐
相关产品推荐

