使用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
相关产品推荐
相关产品推荐

