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

使用OpenIdConnect时避免未授权请求被重定向至登录页

问题描述

我正在搭建一个基于C#和React的Web应用,采用C#后端作为Backend-For-Frontend(BFF),使用Cookie认证方式,参考相关教程并采用最新C#/React模板。

认证功能可正常工作,但访问带有[Authorize]特性的端点时,会收到302重定向至/Account/Login?ReturnUrl=(...),我希望无有效认证Cookie时返回401状态码。

网络请求截图

展示请求被重定向的截图

当前认证配置代码

Program.cs中的配置

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(o =>
{
    o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    o.Cookie.SameSite = SameSiteMode.Strict;
    o.Cookie.HttpOnly = true;
})
.AddOpenIdConnect("Auth0", options => AuthenticationExtensions.ConfigureOpenIdConnect(options, configuration));

AuthenticationExtensions.ConfigureOpenIdConnect实现

internal static void ConfigureOpenIdConnect(OpenIdConnectOptions options, IConfiguration configuration)
{
    options.Authority = $"https://{configuration["Auth0:Domain"]}";

    options.ClientId = configuration["Auth0:ClientId"];
    options.ClientSecret = configuration["Auth0:ClientSecret"];

    options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
    options.ResponseMode = OpenIdConnectResponseMode.FormPost;

    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("offline_access");

    options.CallbackPath = new PathString("/callback");
    options.ClaimsIssuer = "Auth0";
    options.SaveTokens = true;

    options.Events = new OpenIdConnectEvents
    {
        OnRedirectToIdentityProviderForSignOut = (context) =>
        {
            var logoutUri = $"https://{configuration["Auth0:Domain"]}/v2/logout?client_id={configuration["Auth0:ClientId"]}";

            var postLogoutUri = context.Properties.RedirectUri;
            if (!string.IsNullOrEmpty(postLogoutUri))
            {
                if (postLogoutUri.StartsWith("/"))
                {
                    // 转换为绝对路径
                    var request = context.Request;
                    postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
                }
                logoutUri += $"&returnTo={Uri.EscapeDataString(postLogoutUri)}";
            }
            context.Response.Redirect(logoutUri);
            context.HandleResponse();

            return Task.CompletedTask;
        },
        // 我原本期望这些事件中的一个能生效,但并没有。
        OnRedirectToIdentityProvider = context => {
            context.Response.StatusCode = 401;
            context.HandleResponse();
            return Task.CompletedTask;
        },
        OnAuthenticationFailed = context => {
            context.Response.StatusCode = 401;
            context.HandleResponse();
            return Task.CompletedTask;
        },
        OnAccessDenied = context => {
            context.Response.StatusCode = 401;
            context.HandleResponse();
            return Task.CompletedTask;
        }
    };
}
解决方案

问题出在Cookie认证方案的默认挑战行为上——当未认证用户访问受保护端点时,Cookie认证中间件会触发302重定向到登录页,而非返回401。你之前配置的OpenIdConnect事件不生效,是因为当前默认的ChallengeScheme是CookieAuthentication,而非OpenIdConnect。

修改AddCookie的配置,添加OnRedirectToLogin事件覆盖默认重定向行为:

.AddCookie(o =>
{
    o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    o.Cookie.SameSite = SameSiteMode.Strict;
    o.Cookie.HttpOnly = true;
    // 添加以下代码
    o.Events.OnRedirectToLogin = context =>
    {
        // 针对API请求返回401,适配React前端逻辑
        if (context.Request.Path.StartsWithSegments("/api") || !context.Request.Headers.Accept.Contains("text/html"))
        {
            context.Response.StatusCode = StatusCodes.Status401Unauthorized;
            return Task.CompletedTask;
        }
        // 页面请求保留原有重定向逻辑
        context.Response.Redirect(context.RedirectUri);
        return Task.CompletedTask;
    };
})

可选简化方案

如果所有请求都不需要重定向,直接返回401,可简化为:

o.Events.OnRedirectToLogin = context =>
{
    context.Response.StatusCode = StatusCodes.Status401Unauthorized;
    return Task.CompletedTask;
};

内容的提问来源于stack exchange,提问作者Jakob Busk Sørensen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:10:32