Asp.net core 控制允许使用SSO标识服务器4登录到客户端的用户

Asp.net core 控制允许使用SSO标识服务器4登录到客户端的用户,asp.net-core,asp.net-identity,multi-tenant,identityserver4,Asp.net Core,Asp.net Identity,Multi Tenant,Identityserver4,IdentityServer4提供SSO体验和STS功能。只要客户机按照OAuth OpenId Connect进行验证,SSO就会工作。因此,如果用户的身份是基于cookie的,那么用户就可以使用cookie 我想知道是否有人以多租户方式实现了这一点,以限制用户只允许一组客户端(这意味着SSO在它们之间仍然有效——让我们将组称为租户)。当涉及到不允许的用户和客户端时,identity server应该将他们带到登录屏幕 启动时的配置-用户存储的AsNetIdentity servic

IdentityServer4提供SSO体验和STS功能。只要客户机按照OAuth OpenId Connect进行验证,SSO就会工作。因此,如果用户的身份是基于cookie的,那么用户就可以使用cookie

我想知道是否有人以多租户方式实现了这一点,以限制用户只允许一组客户端(这意味着SSO在它们之间仍然有效——让我们将组称为租户)。当涉及到不允许的用户和客户端时,identity server应该将他们带到登录屏幕

启动时的配置-用户存储的AsNetIdentity

     services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddUserManager<CustomUserManager>()
                .AddSignInManager<CustomSignInManager>()
                .AddDefaultTokenProviders();
            //TODO Tenant based cookie SaasKit/Finbuckle
            services.ConfigureApplicationCookie(cookieOptions =>
            {
                cookieOptions.Cookie = new Microsoft.AspNetCore.Http.CookieBuilder
                {
                    Name="Tenant_Cookie"
                };
            });   

 var builder = services.AddIdentityServer(options =>
                {
                    options.Events.RaiseErrorEvents = true;
                    options.Events.RaiseInformationEvents = true;
                    options.Events.RaiseFailureEvents = true;
                    options.Events.RaiseSuccessEvents = true;
                }).AddSigningCredential(GetSigningCertificate("my", "a7 e2 f5 f7 9a b8 8c 86 2c 37 f5 22 1b ea 8c 19 b1 58 99 3c", true))                  
                .AddResponseGenerators()
                .AddCustomAuthorizeRequestValidator<TenantAuthorizeRequestValidator>()
                .AddCustomTokenRequestValidator<TenantTokenRequestValidator>()
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryApiResources(Config.GetApiResources())
                .AddInMemoryClients(Config.GetClients())
                .AddProfileService<CustomProfileService>()
                .AddAspNetIdentity<ApplicationUser>();
租户授权请求验证程序-验证客户端和租户

 public class TenantAuthorizeRequestValidator : ICustomAuthorizeRequestValidator
{
    HttpContext _context;
    ITenantService _tenantService;
    public TenantAuthorizeRequestValidator(IHttpContextAccessor contextAccessor,ITenantService tenantService)
    {
        _context = contextAccessor.HttpContext;
        _tenantService = tenantService;
    }
    public Task ValidateAsync(CustomAuthorizeRequestValidationContext context)
    {
        if (!context.Result.IsError)
        {
            var tenant = context.Result.ValidatedRequest.GetTenant();
            if (!string.IsNullOrEmpty(tenant))
            {                  
                if (!_tenantService.IsValidClient(tenant,context.Result.ValidatedRequest.ClientId))
                {
                    context.Result.IsError = true;
                    context.Result.Error = OidcConstants.AuthorizeErrors.UnauthorizedClient;
                }
                context.Result.ValidatedRequest.ClientClaims.Add(new Claim(
                TenantConstants.TokenKey,
                tenant,
                IdentityServerConstants.ClaimValueTypes.Json));
            }             


            //Find a way to respond the error message
        }

        return Task.CompletedTask;
    }
}
数据库就像

public static Dictionary<string, string[]> TenantClients()
    {
        return new Dictionary<string, string[]>()
        {
            { "tenant1",new string[]{ "tenant1.mvc","tenant1.mvc2" } },
            { "tenant2",new string[]{ "tenant2.mvc" } }
        };
    }
public static Dictionary<string, string[]> ClientUsers()
    {
        return new Dictionary<string, string[]>()
        {
            { "tenant1.mvc", new string[]{"alice","bob"} },
            { "tenant1.mvc2", new string[]{"alice","bob"} },
            { "tenant2.mvc", new string[]{"alice"}}
        };
    }
公共静态字典租户客户端()
{
返回新字典()
{
{“tenant1”,新字符串[]{“tenant1.mvc”,“tenant1.mvc2”},
{“tenant2”,新字符串[]{“tenant2.mvc”}
};
}
公共静态字典ClientUsers()
{
返回新字典()
{
{“tenant1.mvc”,新字符串[]{“alice”,“bob”},
{“tenant1.mvc2”,新字符串[]{“alice”,“bob”},
{“tenant2.mvc”,新字符串[]{“alice”}
};
}
我正在验证客户机和租户,也验证客户机和用户。但是,我们无法实现基于租户的cookie,因此不同的登录将使用不同的cookie在同一浏览器会话上工作。Saaskit似乎不能很好地与AspnetCore2.0配合使用,无法找到与finbuckle配合使用的方法


问题-如何设置租户的cookie名称?基于上下文acr值从请求中解析。这种方法有效吗?

我们最终向用户帐户添加了一组额外的特定于客户端的声明,并根据传入的声明设置授权策略

比如说-

Api资源希望根据令牌中的作用域限制访问,这对于客户端验证很好,对于用户验证,则在令牌中查找特定声明并提供访问权限

使用上述方法,我们必须维护通过UI访问的用户的声明,以及在没有用户的情况下访问服务器到服务器的其他客户端的声明


虽然这不是最好的方法,但它解决了我们当前的需求。

我们的方法是,您需要在启动时为每个租户创建几个AddCookie,每个租户有自己的方案名称


然后在ICCustomAuthorizerRequestValidator中,将方案名称设置为与为租户创建的方案相同(因此可能需要定义一种常见格式,如Cookies-MyTenantId 1或Cookies-MyTenantId 2)。这样,将为每个租户创建一个不同的cookie。

我认为您混合了身份验证和授权策略。定义谁有权访问策略服务器的工作不是身份服务器的工作。我同意DalmTo的观点。在这里检查我的答案-。基本上,您混合了
授权
身份验证
,您不应该这样做。我的情况类似,但使用的是不同的ID提供者。我们使用我们的IDP进行身份验证,并传回我们网站上的登录页面。从那里,该网站将在我们的数据库中查找用户,看看他们是否有权访问该网站。如果是这样,我们会给他们一个cookie并设置声明等。这是您感兴趣的事情,还是您希望将授权保留在您的站点之外?@m3n7alsnak3当涉及到角色时,将身份验证和授权分开是有意义的,因为每个客户端中的用户角色可能不同。我们的IDM实现正试图减少客户端应用程序的工作量,因此我们可以通过配置在我们的应用程序中使用它。我们可以很容易地在客户端检查授权的索赔政策,这需要用户和客户端验证。但是acr_值租户用途有点混乱@DalmTo感谢将两者分开是有意义的(因为框架设计师也建议这样做)。但基于客户的索赔策略将是管理此问题的最简单方法。
public static Dictionary<string, string[]> TenantClients()
    {
        return new Dictionary<string, string[]>()
        {
            { "tenant1",new string[]{ "tenant1.mvc","tenant1.mvc2" } },
            { "tenant2",new string[]{ "tenant2.mvc" } }
        };
    }
public static Dictionary<string, string[]> ClientUsers()
    {
        return new Dictionary<string, string[]>()
        {
            { "tenant1.mvc", new string[]{"alice","bob"} },
            { "tenant1.mvc2", new string[]{"alice","bob"} },
            { "tenant2.mvc", new string[]{"alice"}}
        };
    }