Blazor应用中AspNetCore DataProtection导致OIDC登录循环问题
我搭建的Duende Identity Server在WebAPI和React应用中运行正常,但开发Blazor应用时遇到问题。
服务端认证配置
builder.Services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie() .AddOpenIdConnect("oidc", options => { options.Authority = "https://account.wherever.co.uk"; options.ClientId = "blazor_experiments"; options.ClientSecret = "secret"; options.ResponseType = "code"; options.GetClaimsFromUserInfoEndpoint = false; options.Scope.Add("openid"); options.Scope.Add("profile"); // IdentityResourceClaims means this gets role. options.Scope.Add("offline_access"); // Causes refresh token to be provided. options.GetClaimsFromUserInfoEndpoint = true; options.Events = new Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectEvents { OnRedirectToIdentityProvider = context => { // Logging correlation ID. context.Request.Headers.Add(LoggerScopeMiddleware.LogCorrelationIdHeaderName, context.HttpContext.TraceIdentifier); // Done. return Task.FromResult(0); } }; options.CallbackPath = "/signin-oidc"; options.SignedOutCallbackPath = "/signout-callback-oidc"; });
问题现象
运行应用后,访问需授权页面会触发OIDC流程:浏览器跳转到IdentityServer的authorize端点完成登录,返回项目的/signin-oidc并设置.AspNetCore.CookiesC1、.AspNetCore.CookiesC2、.AspNetCore.CookiesC3三个Cookie。但随后访问授权页面时,会再次触发OIDC流程,循环往复直至IdentityServer返回429(请求过多)错误。
相关日志
项目控制台出现大量如下日志:
Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector: Trace: Performing protect operation to key {bb49856c-dd11-4a42-89c0-ff06d8421485} with purposes ('MyApplication', 'Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler', 'oidc', 'v1'). Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector: Trace: Performing protect operation to key {bb49856c-dd11-4a42-89c0-ff06d8421485} with purposes ('MyApplication', 'Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler', 'System.String', 'oidc', 'v1').
已尝试的解决方案
我在启动项中配置了builder.Services.AddDataProtection(),与IdentityServer及正常运行的WebAPI项目配置一致,也尝试过移除该配置,或使用以下配置:
builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"C:\Work\AspNetCoreDataProtection")) .SetApplicationName("BlazorThing");
但均无效果,请问问题出在哪里?
核心原因分析
这种无限重定向的核心是Blazor应用无法正确识别已登录的Cookie身份,导致每次访问授权页面都判定为未认证,重复触发OIDC挑战流程。常见诱因包括:
1. 未适配Blazor运行模式的认证配置
Blazor Server和WebAssembly的认证逻辑差异极大:
- 若为Blazor WebAssembly:不应使用ASP.NET Core服务器端的
AddAuthentication+AddOpenIdConnect组合,需改用WASM专属的AddOidcAuthentication组件,因为WASM是客户端认证模型; - 若为Blazor Server:Cookie配置需适配SignalR通信,
SameSite、HttpOnly等属性设置不当会导致身份无法在SignalR连接中传递。
2. Cookie Scheme配置不明确
当前AddCookie()未显式指定Scheme名称,而DefaultScheme设为"Cookies",可能导致Cookie认证Handler无法正确关联。需显式绑定Scheme并调整Cookie属性:
.AddCookie("Cookies", options => { options.Cookie.Name = ".BlazorAuthCookie"; options.Cookie.SameSite = SameSiteMode.Lax; options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; })
3. 声明映射或授权规则错误
如果授权页面使用了角色授权(如[Authorize(Roles = "Admin")]),但IdentityServer返回的角色声明未被正确映射,会导致授权失败,进而触发重新认证。需补充声明映射配置:
options.ClaimActions.MapJsonKey("role", "role"); options.TokenValidationParameters = new TokenValidationParameters { RoleClaimType = "role" };
4. DataProtection密钥不兼容
若Blazor应用与IdentityServer的DataProtection密钥未共享,会导致Cookie无法被正确解密,认证直接失败。需确保两者使用相同的密钥存储:
builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"\\shared-storage\dataprotection-keys")) .SetApplicationName("SharedAppName");
(注意:共享目录需给应用分配读写权限)
针对性解决步骤
确认Blazor运行模式:
- WebAssembly:替换认证配置为
builder.Services.AddOidcAuthentication(options => { ... }),使用WASM专属OIDC组件; - Server:调整Cookie配置,显式指定Scheme并适配SignalR需求。
- WebAssembly:替换认证配置为
排查授权逻辑:
- 暂时用
[Authorize(AuthenticationSchemes = "Cookies")]强制指定认证Scheme,验证是否能识别身份; - 移除角色授权,测试基础认证是否正常,逐步缩小问题范围。
- 暂时用
验证Cookie有效性:
- 用浏览器开发者工具查看Cookie的
expires、domain、path属性是否正确; - 检查IdentityServer返回的ID Token/Access Token是否有效,可通过IdentityServer日志验证。
- 用浏览器开发者工具查看Cookie的
内容的提问来源于stack exchange,提问作者Richard Barraclough

