c# - signin-oidc 重定向时关联失败
问题描述
在 NGINX 负载均衡器后面的虚拟机上托管时,尝试对 .NET Core 3.1 Web 应用程序进行身份验证时遇到以下问题(本地它按预期工作,我目前在负载均衡器中只有一个虚拟机):
例外:关联失败。位置不明
异常:处理远程登录时遇到错误。Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler.HandleRequestAsync()
我做了很多研究并尝试了十几个修复程序,但似乎没有一个有效。以下是我的代码片段:
启动.Configure()
// Initialize the ping options and get default values from the config
var pingOptions = Configuration.GetSection("PingOAuthWebOptions").Get<PingOAuthWebOptions>();
// Testing Stack OVerflow Example
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "oidc";
})
.AddCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(10000);
options.Cookie.Name = "PINGSESSION";
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = pingOptions.Authority;
options.ClientId = pingOptions.ClientId;
options.ClientSecret = pingOptions.ClientSecret;
options.ResponseType = OpenIdConnectResponseType.Code;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid"); // Added this
options.SaveTokens = true;
options.Events = new OpenIdConnectEvents()
{
OnRedirectToIdentityProvider = async ctx =>
{
// Change from "HTTP" to "HTTPS" if requested and necessary
if (pingOptions.ForceSecureRedirect && ctx.ProtocolMessage.RedirectUri.StartsWith("http:"))
{
ctx.ProtocolMessage.RedirectUri = ctx.ProtocolMessage.RedirectUri.Replace("http:", "https:");
}
await Task.FromResult(0);
},
OnUserInformationReceived = ctx =>
{
var accessToken = ctx.ProtocolMessage.AccessToken;
var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessToken);
var appIdentity = new ClaimsIdentity(jwt.Claims);
// Add app role
appIdentity.AddClaim(new Claim(ClaimTypes.Role, "Superuser"));
ctx.Principal.AddIdentity(appIdentity);
return Task.CompletedTask;
},
};
});
启动.ConfigureServices()
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
var forwardedHeaderOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
};
forwardedHeaderOptions.KnownNetworks.Clear();
forwardedHeaderOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardedHeaderOptions);
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseSession();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
最后,我尝试过的一些事情:
services.Configure<ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto; options.ForwardLimit = 2; //Limit number of proxy hops trusted options.KnownNetworks.Clear(); options.KnownProxies.Clear(); });
和
app.UseHttpsRedirection();
和
CookiePolicyOptions cookiePolicy = new CookiePolicyOptions() { Secure = CookieSecurePolicy.Always, };
和
redirectContext.ProtocolMessage.State = options.StateDataFormat.Protect(redirectContext.Properties);
和
app.Use((context, next) => { context.Request.Scheme = "https"; return next(); });
解决方案
更新:在使用 OP 进行一些测试后,似乎 auth cookie 因大小而被 NGINX 阻止。通过更改 NGINX 配置解决了问题: https ://unix.stackexchange.com/a/605614
proxy_buffers 8 16k; # Buffer pool = 8 buffers of 16k
proxy_buffer_size 16k; # 16k of buffers from pool used for headers
您能否检查一下您是否能够在开发人员中运行以下配置?在 NGINX 后面测试实例之前,请确保您已向 OpenId Connect 提供程序注册该 URL。
还要检查 X-Forwarded-For 和 X-Forwarded-Proto 是否已传递到您的应用程序。在服务器更改后,我遇到过几次问题。
我建议使用干净的应用程序对此进行测试,作为概念验证 (POC)。当 POC 在所有环境中启动并运行时,您可以将更改应用到现有代码库。
在 Startup.ConfigureServices
var openIdConnectSettings = new OpenIdConnectSettings();
Configuration.GetSection("OpenIdConnect").Bind(openIdConnectSettings);
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = openIdConnectSettings.Authority;
options.ClientId = openIdConnectSettings.ClientId;
options.ClientSecret = openIdConnectSettings.ClientSecret;
options.ResponseType = OpenIdConnectResponseType.Code;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid");
options.SaveTokens = true;
});
在 Startup.Configure
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseCookiePolicy();
}
else
{
app.UseStatusCodePagesWithReExecute( ...
// required in order to get https for OpenIdConnect
// must come before app.UseAuthentication();
var forwardedHeaderOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
};
forwardedHeaderOptions.KnownNetworks.Clear();
forwardedHeaderOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardedHeaderOptions);
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
....
配置类
public class OpenIdConnectSettings
{
public string Authority { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
}
推荐阅读
- azure-cosmosdb - 如何在 Azure Cosmos DB 模拟器中访问更改源
- cypress - cypress CLI 可以区分内部错误和一个失败的测试吗?
- shadow-dom - 有没有办法防止创建#shadow-root
- android - 可以使用 ndk 和 tcc 进行 android 应用程序开发吗?
- amazon-web-services - AWS ECS Fargate 蓝绿色部署 - 第二个目标组一直未能通过健康检查
- spring - 当从同一个 bean 调用时,Transactional.TxType.REQUIRES_NEW 是否会启动一个新事务?
- javascript - 反应本机平面列表中的groupby
- c++ - 函数参数包总是包扩展是什么意思,所以它们声明的类型必须至少包含一个参数包?
- tensorflow - 将经过训练的 HDF5 模型加载到 Rust 中以进行预测
- sql - 仅对不同的组值求和