.NET Core 6中Authorize特性引发OIDC登录无限重定向循环如何解决
.NET Core 6集成IdentityServer4访问受保护页面无限重定向问题
问题现象
- 手动触发外部登录流程运行正常:访问应用登录页选择外部登录后,可正常跳转至IdentityServer站点完成认证,重定向回本应用后ASP.NET Core Identity可基于返回令牌完成本地登录,全流程无异常
- 未认证状态下直接访问标记
[Authorize]特性的视图时,会直接跳转至IdentityServer登录页(不会进入应用自身登录页),完成登录重定向回应用后,本地登录逻辑未执行,会再次重定向至IdentityServer,触发无限重定向循环 - 基架生成ASP.NET Core Identity Razor页面源码调试确认:手动触发登录时所有流程节点(重定向回应用、基于身份令牌完成本地登录)均正常执行;直接访问带
[Authorize]特性的页面时,本地登录流程完全未触发 - 已确认
OnTokenResponseReceived事件可正常接收Access Token与Id Token,令牌无时间偏移问题,字段值均符合预期,浏览器中已写入相关Cookie
现有身份认证配置
var builder = WebApplication.CreateBuilder(args); var connectionString = builder.Configuration.GetConnectionString("MvcClientContextConnection") ?? throw new InvalidOperationException("Connection string 'MvcClientContextConnection' not found."); builder.Services.AddDbContext<MvcClientContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SaveTokens = true; options.Authority = "https://localhost:5001"; options.ClientId = "mvc"; options.ClientSecret = "secret"; options.ResponseType = OpenIdConnectResponseType.Code; options.Scope.Add("profile"); options.Scope.Add("email"); options.GetClaimsFromUserInfoEndpoint = true; options.RequireHttpsMetadata = false; }); builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false) .AddEntityFrameworkStores<MvcClientContext>() .AddDefaultTokenProviders();
调试采集信息
Token接收事件调试代码
options.Events.OnTokenResponseReceived = n => { return Task.FromResult(0); };
返回的Id Token内容
{ "nbf": 1655641328, "exp": 1655641628, "iss": "https://localhost:5001", "aud": "mvc", "nonce": "637912381209176720.ZDIwZWJhZjUtYWJkNi00OWY2LTliZDMtYjdhNjI3NTA3YjFkNjdlOGIxMDQtNmUwYy00ZmUxLTk4MzUtNDI5YjEwODZkOGRh", "iat": 1655641328, "at_hash": "UJwjVbUn4onLus-a6Wo8qA", "s_hash": "UAsrV-r-CNCIK73V1KT0iw", "sid": "6E7E25E03BFD3D1BEDB2FE6980EC9287", "sub": "3d8f3e39-d9c4-4e75-88f4-07d359e21052", "auth_time": 1655640810, "idp": "local", "name": "myuser", "email": "myuser@mysite.dk", "preferred_username": "myuser@mysite.dk", "email_verified": true, "amr": [ "pwd" ] }
Cookie状态截图

根因分析
问题核心为认证方案注册冲突、Cookie校验与写入方案不匹配:
- 手动调用
AddAuthentication()注册了名为Cookies的自定义Cookie认证方案,后续调用AddDefaultIdentity()时,ASP.NET Core Identity会自动注册自身使用的默认Cookie方案(名称为Identity.Application),两个独立Cookie方案同时生效 - 配置中默认Challenge方案设为
oidc,未认证访问受保护页面时会直接触发OIDC挑战跳转至IdentityServer,跳过应用本地登录页逻辑 - OIDC认证完成后,令牌声明写入的是手动注册的
Cookies方案,但[Authorize]特性默认校验的是Identity注册的Identity.Application方案下的Cookie,校验不通过会再次触发OIDC挑战,最终形成无限重定向循环 - 手动点击外部登录时,显式调用了Identity的登录逻辑,写入的是
Identity.Application方案的Cookie,因此流程可正常执行
修复方案
移除独立编写的AddAuthentication()配置块,统一使用Identity默认注册的认证方案,修改后的配置代码如下:
var builder = WebApplication.CreateBuilder(args); var connectionString = builder.Configuration.GetConnectionString("MvcClientContextConnection") ?? throw new InvalidOperationException("Connection string 'MvcClientContextConnection' not found."); builder.Services.AddDbContext<MvcClientContext>(options => options.UseSqlServer(connectionString)); // 保留Identity默认配置 builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false) .AddEntityFrameworkStores<MvcClientContext>() .AddDefaultTokenProviders(); // 追加OIDC认证配置,不修改默认认证方案 builder.Services.AddAuthentication() .AddOpenIdConnect("oidc", options => { options.SaveTokens = true; options.Authority = "https://localhost:5001"; options.ClientId = "mvc"; options.ClientSecret = "secret"; options.ResponseType = OpenIdConnectResponseType.Code; options.Scope.Add("profile"); options.Scope.Add("email"); options.GetClaimsFromUserInfoEndpoint = true; options.RequireHttpsMetadata = false; }); // 配置应用Cookie登录路径,未认证时先跳转至本地登录页,可自行选择登录方式 builder.Services.ConfigureApplicationCookie(options => { options.LoginPath = "/Identity/Account/Login"; });
如果不需要经过本地登录页、要求未认证时直接跳转IdentityServer,只需在AddAuthentication配置中显式指定所有默认方案与Identity使用的方案一致,保证OIDC登录完成后写入的Cookie方案与[Authorize]校验的方案完全统一即可。
内容的提问来源于stack exchange,提问作者Bildsoe
相关产品推荐
相关产品推荐

