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

.NET 6迁移至.NET 8后IIS部署出现AntiforgeryValidationException错误求助

问题:.NET 8迁移后IIS部署出现防伪令牌解密失败错误

我们正将项目从.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 18:44:51