ASP.NET Core 6部署IIS后Identity认证异常:Question控制器无法访问
问题描述
在IIS上部署的ASP.NET Core 6项目中,使用Identity处理认证与授权时出现异常:登录成功后多数MVC控制器可正常访问,但访问Question控制器的/Questions/Asked/List(对应MyQuestions方法)时,即便用户处于已认证状态,仍会被重定向到/Account/Login页面。本地Visual Studio 2022运行完全正常,移除授权特性、测试其他带授权特性的控制器后问题依旧。
排查与解决方案
1. 中间件顺序错误
本地化中间件UseRequestLocalization被放置在认证中间件之后,可能导致文化Cookie处理干扰身份认证Cookie的读取逻辑,进而引发认证失效。
修复方案:调整中间件顺序,将UseRequestLocalization移至UseRouting之前:
var app = builder.Build(); // ... 环境配置代码 ... // 先执行本地化配置 var localizationOptions = app.Services.CreateScope().ServiceProvider .GetService<IOptions<RequestLocalizationOptions>>().Value; app.UseRequestLocalization(localizationOptions); app.UseSession(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); // ... 其他中间件及路由配置 ...
2. 自定义授权特性未处理未认证场景
自定义Authorization特性中未先校验用户是否已认证,若认证Cookie未正确读取,访问User.Claims会抛出异常,被框架捕获后触发默认登录重定向,而非预期的访问拒绝页面。
修复方案:增强授权特性逻辑,先校验认证状态:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public class Authorization : Attribute, IAuthorizationFilter { public Claim Claim { get; set; } public Authorization(string claimType) { this.Claim = new Claim(claimType, "true"); } public void OnAuthorization(AuthorizationFilterContext context) { // 先校验用户是否已认证 if (!context.HttpContext.User.Identity?.IsAuthenticated ?? true) { context.Result = new ChallengeResult(); return; } try { var userHasClaim = context.HttpContext.User.Claims.Any(x => string.Equals(x.Type, this.Claim.Type, StringComparison.OrdinalIgnoreCase) && string.Equals(x.Value, this.Claim.Value, StringComparison.OrdinalIgnoreCase)); if (!userHasClaim) { context.Result = new RedirectResult("/Error/Access-Denied"); } } catch { context.Result = new RedirectResult("/Error/Access-Denied"); } } }
3. IIS环境下Cookie配置缺失
生产环境中Cookie的SameSite、Secure等属性未明确配置,可能导致Cookie无法在IIS环境下正确传递。
修复方案:完善Cookie配置:
service.ConfigureApplicationCookie((cookie) => { cookie.Cookie.HttpOnly = true; cookie.ExpireTimeSpan = TimeSpan.FromMinutes(20); cookie.SlidingExpiration = true; cookie.Cookie.SameSite = SameSiteMode.Lax; cookie.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 启用HTTPS时设置 cookie.LoginPath = "/Account/Login"; cookie.AccessDeniedPath = "/Error/Access-Denied"; });
4. Session与认证Cookie冲突
Session Cookie与Identity认证Cookie名称默认可能重叠,在IIS环境下引发Cookie隔离问题。
修复方案:自定义Session Cookie名称:
service.AddSession((options) => { options.IOTimeout = TimeSpan.FromMinutes(20); options.IdleTimeout = TimeSpan.FromMinutes(20); options.Cookie.Name = ".ForumApp.Session"; // 自定义名称避免冲突 });
5. 路由匹配优先级问题
自定义路由[Route("/Questions/Asked/List")]与默认路由规则可能存在匹配冲突,导致请求未正确映射到目标方法。
修复方案:调整路由配置,确保唯一性:
[Route("[controller]")] public class QuestionController : Controller { [Authorization(ClaimList.MyQuestions)] [HttpGet("Asked/List")] public async Task<IActionResult> MyQuestions() { // ... 原有逻辑 ... } }
内容的提问来源于stack exchange,提问作者babak madadi

