.NET 6迁移至.NET 8后IIS部署出现AntiforgeryValidationException错误求助
我们正将项目从.NET 6.0迁移至.NET 8.0,期间遇到如下问题:我们有一个ASP.NET Core MVC应用,需连接IdentityServer4进行身份验证。迁移后本地运行正常,但部署到IIS时抛出错误:
反序列化令牌时引发异常。
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException:无法解密防伪令牌。
System.Security.Cryptography.CryptographicException:密钥{f203edca-73bf-4b5f-ae0a-3d0a2c304ab4}在密钥环中未找到。更多信息请访问https://aka.ms/aspnet/dataprotectionwarning在Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
在Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
在Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
--- 内部异常堆栈跟踪结束 ---
在Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
在Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext)
2024-06-07 16:46:16.191 +05:30 [ERR] 无法获取自动登录凭据,正在重定向至登录页面。
恳请各位提供帮助,提前感谢。
更新-1:客户端配置
ConfigureServices() 代码:
services.AddMvc(options => options.EnableEndpointRouting = false) .AddSessionStateTempDataProvider(); services.AddSession(); services.AddAuthorization(options => { options.AddPolicy("UserPermission", policy => policy.Requirements.Add(new UserPermissionAuthorization())); }); services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie(options => { options.Cookie.HttpOnly = true; options.Cookie.Name = CookieAuthenticationDefaults.AuthenticationScheme; options.ExpireTimeSpan = TimeSpan.FromSeconds(loginExpiryinSeconds); options.SlidingExpiration = false; }) .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { options.ClientId = axiClientId; options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Authority = idServerUrl; options.RequireHttpsMetadata = false; options.SaveTokens = true; options.Events.OnRedirectToIdentityProvider = context => { context.ProtocolMessage.Prompt = "login"; return Task.CompletedTask; }; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); }); services.AddHsts(options => { options.IncludeSubDomains = true; options.MaxAge = TimeSpan.FromDays(365); }); services.AddAntiforgery(options => { options.FormFieldName = "AntiforgeryFieldname"; options.HeaderName = "X-CSRF-TOKEN-HEADERNAME"; options.SuppressXFrameOptionsHeader = false; });
Configure() 代码:
app.Use(async (context, next) => { context.Response.Headers.Add("X-Xss-Protection", "1; mode=block"); context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN"); context.Response.Headers.Add("X-Content-Type-Options", "nosniff"); context.Response.Headers.Add("X-Permitted-Cross-Domain-Policies", "none"); await next(); }); app.UseSession(); app.UseStaticFiles(); app.UseAuthentication(); app.UseRouting(); app.UseAuthorization(); app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax }); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); app.Use(async (context, next) => { context.Response.Headers.Add("Content-Security-Policy-Report-Only", "default-src 'self' http://code.jquery.com http://ajax.aspnetcdn.com http://cdnjs.cloudflare.com http://localhost:*; script-src 'self' http://code.jquery.com http://ajax.aspnetcdn.com http://cdnjs.cloudflare.com http://localhost:*; style-src 'self' http://code.jquery.com http://ajax.aspnetcdn.com http://cdnjs.cloudflare.com http://maxcdn.bootstrapcdn.com; font-src 'self' http://maxcdn.bootstrapcdn.com; img-src 'self' http://www.w3.org/ http://code.jquery.com; frame-src 'self'"); await next(); });
解决方案
1. 统一DataProtection密钥存储位置
ASP.NET Core默认会为本地开发和IIS服务器生成独立的密钥环,导致跨环境加密/解密不兼容。需显式配置共享密钥存储路径:
在ConfigureServices中添加:
services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"D:\YourAppSharedKeys")) // 替换为服务器实际可访问路径 .SetApplicationName("YourUniqueAppName"); // 本地和服务器需保持一致
注意:服务器目录需给IIS应用池账号分配读写权限。
2. 清理旧Cookie
用户浏览器中可能留存了.NET 6环境下生成的防伪令牌Cookie,这些Cookie无法被.NET 8解密。可:
- 指导用户清除浏览器缓存与Cookie
- 在应用中添加逻辑,检测到无效Cookie时自动清除并重新生成
3. 检查IIS应用池配置
- 确保应用池的
.NET CLR版本设置为无托管代码(ASP.NET Core为自托管模式) - 确认应用池账号对密钥存储目录有读写权限
- 避免应用池频繁重启,防止密钥环被重新生成
4. 调整中间件顺序
当前配置中UseCookiePolicy位于UseAuthorization之后,可能导致Cookie配置未正确生效。正确顺序应为:
app.UseStaticFiles(); app.UseCookiePolicy(); // 移至UseAuthentication之前 app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); app.UseEndpoints(endpoints => { ... });
内容的提问来源于stack exchange,提问作者Naresh Parmar

