【发布时间】:2019-04-28 15:53:09
【问题描述】:
我正在 ASP.NET Core 2.1 中开发一个应用程序,并在 Kubernetes 集群上运行它。我已经使用 OpenIDConnect 实现了身份验证,使用 Auth0 作为我的提供者。
这一切都很好。标有[Authorize] 属性的操作或控制器将匿名用户重定向到身份提供者,他们登录,重定向回来,Bob 是你的叔叔。
当我将部署扩展到 2 个或更多容器时,问题开始出现。当用户访问应用程序时,他们会登录,并且根据在回调期间为他们提供服务的容器,身份验证成功或失败。即使在身份验证成功的情况下,当用户点击他们未授权的容器时,反复 F5-ing 最终将重定向到身份提供者。
我的思路是,使用 cookie 身份验证,用户在浏览器中存储一个 cookie,该 cookie 与每个请求一起传递,应用程序对其进行解码并获取 JWT,然后从中获取声明,并且用户已通过身份验证。这使得整个事情无状态,因此无论容器服务于请求如何,都应该工作。然而,如上所述,它似乎并没有真正以这种方式工作。
我在Startup.cs 中的配置如下:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect("Auth0", options =>
{
options.Authority = $"https://{Configuration["Auth0:Domain"]}";
options.ClientId = Configuration["Auth0:ClientId"];
options.ClientSecret = Configuration["Auth0:ClientSecret"];
options.ResponseType = "code";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name"
};
options.SaveTokens = true;
options.CallbackPath = new PathString("/signin-auth0");
options.ClaimsIssuer = "Auth0";
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.ProtocolMessage.SetParameter("audience", "https://api.myapp.com");
// Force the scheme to be HTTPS, otherwise we end up redirecting back to HTTP in production.
// They should seriously make it easier to make Kestrel serve over TLS in the same way ngninx does...
context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace("http://",
"https://", StringComparison.OrdinalIgnoreCase);
Debug.WriteLine($"RedirectURI: {context.ProtocolMessage.RedirectUri}");
return Task.FromResult(0);
}
};
});
我花了几个小时试图解决这个问题,但结果一无所获。我现在唯一能想到的理论上可行的方法是使用粘性负载平衡,但这更多的是应用创可贴而不是实际解决问题。
使用 Kubernetes 的主要原因之一是它的弹性和处理扩展的能力。就目前而言,我只能扩展我的支持服务,而我的主应用程序必须作为单个 pod 运行。这远非理想。
也许某处有某种机制可以与我不知道的特定实例建立关联?
我希望有人能指出我正确的方向。
谢谢!
【问题讨论】:
-
clientkey能不能成为key?
-
如何保存token?在服务器上还是在数据库中?
标签: c# asp.net-core kubernetes openid-connect auth0