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

.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截图

根因分析

问题核心为认证方案注册冲突、Cookie校验与写入方案不匹配:

  1. 手动调用AddAuthentication()注册了名为Cookies的自定义Cookie认证方案,后续调用AddDefaultIdentity()时,ASP.NET Core Identity会自动注册自身使用的默认Cookie方案(名称为Identity.Application),两个独立Cookie方案同时生效
  2. 配置中默认Challenge方案设为oidc,未认证访问受保护页面时会直接触发OIDC挑战跳转至IdentityServer,跳过应用本地登录页逻辑
  3. OIDC认证完成后,令牌声明写入的是手动注册的Cookies方案,但[Authorize]特性默认校验的是Identity注册的Identity.Application方案下的Cookie,校验不通过会再次触发OIDC挑战,最终形成无限重定向循环
  4. 手动点击外部登录时,显式调用了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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:03:27