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

IdentityServer4集成MVC应用登录后出现反复重定向循环问题

问题原因及修复方案

核心错误点1:MVC端认证Scheme不匹配

你在AddAuthentication时将DefaultScheme设为了CookieAuthenticationDefaults.AuthenticationScheme(默认值为Cookies),但实际添加Cookie认证时用的是IdentityServerConstants.ExternalCookieAuthenticationScheme,且OIDC的SignInScheme也指定为了这个外部Scheme:

  • 登录成功后主体验证信息会存在ExternalCookie对应的Cookie里
  • 后续请求到来时,认证中间件会读取默认Cookies Scheme对应的Cookie,根本读不到登录信息,因此判定用户未登录,再次触发OIDC挑战形成循环

修复代码:

将AddAuthentication的默认Scheme和OIDC的SignInScheme统一:

services.AddAuthentication(options =>
{
    // 统一用外部Cookie Scheme作为默认认证方案
    options.DefaultScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie(IdentityServerConstants.ExternalCookieAuthenticationScheme)
.AddOpenIdConnect("oidc", "IdentityServer", options =>
{
    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
    // 删掉错误的ReturnUrlParameter配置,这个属性是指定回调参数名,不是填回调地址
    // options.ReturnUrlParameter = "https://localhost:44346/Home/Foo";
    // 如果要固定回调地址,配置CallbackPath即可,且需要在IdentityServer客户端配置中允许该地址
    options.CallbackPath = "/signin-oidc";
    // 其余配置保持不变
});

核心错误点2:全局授权拦截OIDC回调请求

你给所有控制器加了全局RequireAuthenticatedUser的授权过滤器,OIDC默认回调地址/signin-oidc也会被拦截,回调请求携带的授权码还没被处理就被重定向到IdentityServer,形成循环

修复方案:

允许回调地址匿名访问,可在ConfigureServices中添加如下配置:

services.AddControllersWithViews(options =>
{
    AuthorizationPolicy policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
})
// 给OIDC回调路径添加匿名访问约定
.AddMvcOptions(options =>
{
    options.Conventions.Add(new ActionModelConvention(action =>
    {
        if (action.AttributeRouteInfo?.Template == "signin-oidc")
        {
            action.Filters.Add(new AllowAnonymousFilter());
        }
    }));
})
.AddRazorRuntimeCompilation()
.AddMicrosoftIdentityUI();

核心错误点3:IdentityServer端登录跳转逻辑错误

你在AccountController的Login Post方法中直接跳转IdentityLoginModel.ReturnUrl,这个静态属性大概率没有正确接收请求携带的returnUrl参数,且未验证returnUrl合法性,容易跳转到错误地址

修复代码:

[HttpPost]
#if !DEBUG
[ValidateAntiForgeryToken]
#endif
public async Task<IActionResult> Login([FromForm] IdentityLoginModel identityLoginModel, string returnUrl)
{
    try
    {
        AppIdentityUser identityUser = await _userManager.FindByEmailAsync(identityLoginModel.EmailAddress);
        if (identityUser == null)
        {
            ModelState.AddModelError("", "账号不存在");
            return View(identityLoginModel);
        }
        Microsoft.AspNetCore.Identity.SignInResult signinResult = 
            await _signInManager.PasswordSignInAsync(identityUser.UserName, identityLoginModel.Password, identityLoginModel.IsPersistent, false);

        if (signinResult.Succeeded)
        {
            await _events.RaiseAsync(new UserLoginSuccessEvent(identityLoginModel.EmailAddress, identityUser.Id, identityUser.UserName));
            // 验证returnUrl合法性,避免开放重定向漏洞
            if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            return Redirect("~/");
        }
        else
        {
            ModelState.AddModelError("", "账号或密码错误");
            return View(identityLoginModel);
        }
    }
    catch (Exception ex)
    {
        // TODO: Log error(s)
        return Problem(statusCode: 500);
    }
}

额外检查项

  • 确认IdentityServer中客户端3468的配置:允许的回调地址包含MVC的/signin-oidc路径,允许的授权类型包含code,已配置对应的ClientSecret
  • 确认MVC端CookiePolicy的SameSite配置符合浏览器要求,本地开发可设为SameSiteMode.Lax

内容的提问来源于stack exchange,提问作者traveler3468

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 22:15:01