>我有以下内容:
- Okta 身份管理,带自定义身份验证服务器
- .NET Core Web 应用程序
- .NET Core Web API 应用程序
- NopCommerce 4.2 Web 应用程序
所有这些都在 Azure 应用服务中运行。我构建的 Web 应用和 API 应用协同工作得很好。Web 应用程序将身份验证持有者令牌传递给 API,API 使用 Aspnetcore.Okta 中间件对其进行验证。
但是,我现在需要将我的Nopcommerce应用程序带入折叠。我花了 3 天时间尝试构建一个插件 - 即使是一个基本上什么都不做的插件,除了麻烦之外什么都没有。我使用了他们的"官方"模板,它有自己的问题。所以我决定只使用Facebook外部身份验证插件并开始编辑它。至少现在我有一些我实际上可以使用的东西。
这是我真正陷入困境的地方...我可以只坚持使用 Okta 中间件并完成它吗?我的意思是以下步骤:
- 添加登录操作控制器以覆盖默认的 Nopcommerce 登录操作
- 如果用户未通过身份验证,则发出质询
- 中间件应该选择它并重定向到登录页面(在我现有的 Web 应用程序中(
- 用户登录那里
- 中间件设置会话 cookie 并将用户重定向回 Nopcomm 应用程序
- 现在回到Nopcomm,中间件再次启动,看到cookie,调用/vering端点,然后为关联用户填充ClaimsPrincipal。
我的想法是,如果两个应用程序上的机器键相同,则cookie应该可以正常工作。
您认为这是最好的方法,还是我应该按照 1-4 中的相同步骤进行操作,除了 4 之后,使用查询字符串中的令牌将用户发送回 Nopcomm 站点,然后在 Nopcomm 端手动验证它?
我想我会分享到目前为止的测试结果,因为它发现了一些我真正没有预料到的事情。也许这些事情对你们大多数人来说都是显而易见的/已知的 - 但对我来说,它们绝对被证明是棘手的。
我学到的第一件事是,您必须具体说明应用程序遇到的挑战类型。如果您自托管登录页面,则需要使用:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
如果您使用的是 Okta(或其他 openId 提供程序(登录页面,则需要发出不同类型的质询:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
我学到的是,如果您在 ASP.NET Core应用程序中使用OpenID Connect,并且您正在自托管登录页面,则流程如下所示:
- 用户尝试访问受保护的资源
- [授权] 标记告诉 Okta 中间件注入自身并做它的事情。User.Identity.IsAuthentication是假的,因此它会重定向到cookie选项下设置为登录路径的任何内容:
.AddCookie(options =>
{
options.LoginPath = new PathString("/Account/SignIn");
options.Cookie.Name = ".AspNet.SharedCookie";
})
我的登录页面只是使用 Okta 小部件,因此单击登录会将用户发送到 Okta,Okta 执行其操作,然后将用户发送回应用程序到每个神秘的"授权代码/回调"网址。该 url 由 Okta 中间件处理。
中间件处理从 Okta 发送的令牌,调用/userinfo 终结点以获取声明(假设该属性设置为 true(并填充 ClaimsPrincipal。
这是我错过的部分它还做的是设置一个cookie。从那一刻起,.net 框架将检查该 cookie 以确定用户是谁以及他们是否经过身份验证。我完全误解了这一点。我以为中间件会在后台调用/authorize 或类似的东西。
所以 - 对我来说,这里学到的重要教训是:仅仅因为两个应用程序使用相同的 OpenID 服务器并不意味着它们可以轻松共享身份验证/会话。为了使真正的 SSO 无缝工作,他们还必须共享一个 cookie。这让我想到了我的第二个发现:跨 ASP.NET 核心应用程序共享 cookie。简短的版本是您必须:
a. 在两个应用程序中将 cookie 命名相同 b.使用 IDataProtection 界面将 Cookie 密钥存储在两个应用都可以访问的位置(我选择了 Azure(。 c.确保两个应用的 Cookie 域相同
所以归根结底,这就是我的代码端到端的样子(在每个应用程序的启动中(。我仍在处理Nopcommerce特有的一些奇怪问题,但希望它们很快就会在这里得到解决。
var oktaMvcOptions = new OktaMvcOptions()
{
OktaDomain = oktaDomain,
ClientId = clientId,
ClientSecret = clientSecret,
Scope = new List<string> { "openid", "profile", "email", "address", "groups" },
AuthorizationServerId = authServerId,
GetClaimsFromUserInfoEndpoint = true
};
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(storageContainerName);
var blob = container.GetBlockBlobReference("somefilename.xml");
services.AddDataProtection().SetApplicationName("somesharedappname").PersistKeysToAzureBlobStorage(blob);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = new PathString("/Account/SignIn");
options.Cookie.Name = "somesharedcookiename";
})
.AddOktaMvc(oktaMvcOptions);
我希望这可以帮助那些最终在相同问题上苦苦挣扎的人。如果有人能提出更好的机制来实施这一点,我很想听听你的想法和建议。