【问题标题】:Multi-tenant Authentication using OWIN Pipeline使用 OWIN 管道进行多租户身份验证
【发布时间】:2016-10-22 05:51:06
【问题描述】:

我有一个多租户应用程序,每个租户都可以为 WsFed 或 OpenIdConnect(Azure) 或 Shibboleth(Kentor) 定义自己的元数据 URl、ClientId、权限等。所有租户都存储在 DB 表中,并在 OwinStartup 中注册,如下所示:

        // Configure the db context, user manager and signin manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            //  CookieName = "Kuder.SSO",
            LoginPath = new PathString("/Account/Login-register"),
            Provider = new CookieAuthenticationProvider
            {
                //Enables the application to validate the security stamp when the user logs in.
                //This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });

        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

    OrganizationModel objOrg = new OrganizationModel();
    var orgList = objOrg.GetOrganizationList();
    foreach (OrganizationModel org in orgList)
    {
        switch (org.AuthenticationName)
        {
            case "ADFS":
            WsFederationAuthenticationOptions objAdfs = null;
             objAdfs = new WsFederationAuthenticationOptions
                {
                    AuthenticationType = org.AuthenticationType,
                    Caption = org.Caption,
                    BackchannelCertificateValidator = null,
                    MetadataAddress = org.MetadataUrl,
                    Wtrealm = org.Realm,
                    SignOutWreply = org.Realm,
                    Notifications = new WsFederationAuthenticationNotifications
                    {
                        AuthenticationFailed = context =>
                        {
                            context.HandleResponse();
                            Logging.Logger.LogAndEmailException(context.Exception);
                            context.Response.Redirect(ConfigurationManager.AppSettings["CustomErrorPath"].ToString() + context.Exception.Message);
                            return Task.FromResult(0);
                        }
                    },
                    TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false },
                };
             app.UseWsFederationAuthentication(objAdfs);
                break;
            case "Azure":
                OpenIdConnectAuthenticationOptions azure = null;
                azure = new OpenIdConnectAuthenticationOptions
                {
                    AuthenticationType = org.AuthenticationType,
                    Caption = org.Caption,
                    BackchannelCertificateValidator = null,
                    Authority = org.MetadataUrl,
                    ClientId = org.IDPProvider.Trim(),
                    RedirectUri = org.Realm,
                    PostLogoutRedirectUri = org.Realm, 
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = context =>
                        {
                            context.HandleResponse();
                            Logging.Logger.LogAndEmailException(context.Exception);
                            context.Response.Redirect(ConfigurationManager.AppSettings["CustomErrorPath"].ToString() + context.Exception.Message);
                            return Task.FromResult(0);
                        }
                    },
                    TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false },
                };
                app.UseOpenIdConnectAuthentication(azure);
                break;
            case "Shibboleth":
                var english = CultureInfo.GetCultureInfo("en-us");
                var organization = new Organization();
                organization.Names.Add(new LocalizedName("xxx", english));
                organization.DisplayNames.Add(new LocalizedName("xxx Inc.", english));
                organization.Urls.Add(new LocalizedUri(new Uri("http://www.aaa.com"), english));

                var authServicesOptions = new KentorAuthServicesAuthenticationOptions(false)
               {
                   SPOptions = new SPOptions
                   {
                       EntityId = new EntityId(org.Realm),
                       ReturnUrl = new Uri(org.Realm),
                      Organization = organization,
                   },
                   AuthenticationType = org.AuthenticationType,
                   Caption = org.Caption,
                  SignInAsAuthenticationType = "ExternalCookie",
               };
                authServicesOptions.IdentityProviders.Add(new IdentityProvider(
                new EntityId(org.IDPProvider), authServicesOptions.SPOptions)
                 {
                     MetadataLocation = org.MetadataUrl,
                     LoadMetadata = true,
                    SingleLogoutServiceUrl = new Uri(org.Realm),
                 });
                app.UseKentorAuthServicesAuthentication(authServicesOptions);
                break;
            default:
                break;
        }
    }

当在 Db 中启用同一提供程序(ADFS、Azure 或 Shibboleth)的多个组织时,我会收到错误消息。我试过“app.Map”来扩展它。但虽然不成功。此外,我使用以下代码注销所有提供程序(ADFS 和 Azure),但注销也失败。

Provider 是我跨组织使用的唯一身份验证类型。

HttpContext.GetOwinContext().Authentication.SignOut(provider, Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie, DefaultAuthenticationTypes.ExternalCookie);

寻求帮助/指导。 注意:每当添加新租户时,可以回收 appdomain,不需要动态重建管道以使事情变得复杂。

【问题讨论】:

    标签: azure owin multi-tenant adfs kentor-authservices


    【解决方案1】:

    Kentor.AuthServices 中间件支持多个实例,但您需要为每个实例分配一个特定的ModulePath。没有它,第一个 Kentor.AuthServices 中间件将处理所有传入的请求,并对来自配置有其他实例的 IdentityProviders 的消息抛出错误。

    我知道其他一些 Katana 提供程序具有在回调期间使用的类似“隐藏”端点,但我不知道在加载多个中间件实例时它们会如何表现。

    作为替代方案,Kentor.AuthServices 中间件还支持将多个身份提供者注册到一个实例。然后您可以在运行时添加和删除 IdentityProvider 实例到 KentorAuthServicesAuthenticationOptions 并使其立即生效。但是,如果您为每个租户使用一个中间件用于其他协议,这可能不是一个理想的解决方案。

    【讨论】:

    • 你能展示一些关于如何添加模块路径的sn-p
    • 这是SPOptions中的一个属性
    • 对于不同的提供商,我需要从 IDP 提供各自的身份验证服务吗?
    • 我不明白-如果您需要聊天,请加入gitter.im/KentorIT/authservices
    【解决方案2】:

    难道不能根据 app.MapWhen("tenant1", ctx=> ctx.configureSpecificTenant) 中的条件为每个租户创建不同的 owin 管道

    MapWhen 还接受一个函数,因此您可以将其基于其他条件,例如在列表上具有 foreach 迭代的子域。

    【讨论】:

    • 你能分享一个工作的sn-p吗?租户 1 只能通过 URL 路径识别。即 http://......../tenant1。因此,基于此,我需要匹配我拥有的管道配置并加载它们
    • 我没有可用的 sn-p 但我会尝试类似: var tenants = new List() { new Tenant() { Subdomain = new Subdomain("organisation2") } }; var tenantFromContextParser= new TenantFromContextParser(); foreach(租户中的 var 租户){ portalApp.MapWhen(ctx => tenant.Subdomain == tenantFromContextParser.ParseFromHost(ctx).OrganisationPart, perTenantApp => { perTenantApp.configurePerClient(.....); }); }
    猜你喜欢
    • 2018-12-19
    • 2015-09-23
    • 1970-01-01
    • 2015-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-08
    • 2017-06-08
    相关资源
    最近更新 更多