【问题标题】:Nopcommerce Okta IntegrationNopcommerce Okta 集成
【发布时间】:2020-05-07 13:49:07
【问题描述】:

我有以下几点:

  • 带有自定义身份验证服务器的 Okta 身份管理
  • .net 核心网络应用程序
  • .net core web api 应用程序
  • Nopcommerce 4.2 网络应用程序

所有都在 Azure 应用服务中运行。我构建的 web 应用程序和 api 应用程序可以很好地协同工作。 Web 应用程序将身份验证承载令牌传递给 API,API 使用 Aspnetcore.Okta 中间件对其进行验证。

但是,我现在需要将我的 Nopcommerce 应用程序纳入其中。我花了 3 天时间尝试构建一个插件——即使是一个基本上什么都不做的插件,除了麻烦什么都没有。我使用了他们的“官方”模板,它有自己的问题。所以我决定只使用 Facebook 外部身份验证插件并开始编辑它。至少现在我有一些我可以实际使用的东西。

这是我真正陷入困境的地方......我可以坚持使用 Okta 中间件并完成它吗?我的意思是以下步骤:

  1. 添加登录操作控制器以覆盖默认的 Nopcommerce 登录操作
  2. 如果用户不是authentictad,发出挑战
  3. 中间件应该选择它并重定向到登录页面(在我现有的网络应用中)
  4. 用户在那里登录
  5. 中间件设置会话 cookie 并将用户重定向回 Nopcomm 应用
  6. 现在回到 Nopcomm,中间件再次启动,查看 cookie,调用 /verify 端点,然后为关联用户填充 ClaimsPrincipal。

我的想法是,如果两个应用程序上的机器密钥相同,那么 cookie 应该可以正常工作。

您是否认为这是最好的方法,或者我应该按照 1-4 中的相同步骤,除了 4 之后,使用查询字符串中的令牌将用户发送回 Nopcomm 站点,然后手动验证它Nopcomm 那边?

【问题讨论】:

    标签: asp.net-core asp.net-core-mvc openid nopcommerce okta


    【解决方案1】:

    我想我会分享我的测试结果,因为它发现了一些我真的没想到的东西。也许这些事情对你们大多数人来说是显而易见的/知道的 - 但对我来说,它们肯定被证明是棘手的。

    我学到的第一件重要事情是,您必须针对应用问题的挑战类型进行具体说明。如果您是自托管登录页面,则需要使用:

                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,并且您正在自托管登录页面,则流程如下所示:

    1. 用户尝试访问受保护的资源
    2. [Authorize] 标记告诉 Okta 中间件注入自己并执行其操作。 User.Identity.IsAuthenticated 为 false,因此它重定向到 cookie 选项下设置的任何内容作为登录路径:
                .AddCookie(options =>
                {
                    options.LoginPath = new PathString("/Account/SignIn");
                    options.Cookie.Name = ".AspNet.SharedCookie";
                })
    
    1. 我的登录页面只是使用 Okta 小部件,因此单击登录会将用户发送到 Okta,Okta 会执行它的操作,然后将用户发送回应用程序到每个神秘的“授权码/回调”url .该 url 由 Okta 中间件处理。

    2. 中间件处理从 Okta 发送的令牌,调用 /userinfo 端点以获取声明(假设您将该属性设置为 true)并填充 ClaimsPrincipal。

    3. 这是我错过的部分它还可以设置一个 cookie。从那时起,.net 框架将检查该 cookie 以确定用户是谁以及他们是否已通过身份验证。我完全误解了这一点。我以为中间件会在后台调用 /authorize 或类似的东西。

    所以 - 我在这里学到的重要教训是:仅仅因为两个应用程序使用相同的 OpenID 服务器并不意味着它们可以轻松共享身份验证/会话。为了让真正的 SSO 无缝工作,他们还必须共享一个 cookie。这让我想到了我的第二个发现:跨 ASP.NET 核心应用程序共享 cookie。简短的版本是您必须:

    一个。在两个应用程序中将 cookie 命名为相同 湾。使用 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);
    

    我希望这可以帮助那些最终遇到同样问题的人。如果有人可以提出更好的机制来实现这一点,我很想听听您的想法和建议。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-04
      • 2016-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多