IdentityServer4 提供 SSO 体验以及 STS 功能。一旦客户端根据OAuth OpenId Connect进行验证,SSO就可以工作。所以用户如果身份是基于cookie。
我想知道是否有人为多租户方式实现了这一点,以限制用户只允许一组客户端(意味着 SSO 仍然在它们之间工作 - 让我们将该组称为租户(。当涉及到不允许的用户和客户端时,身份服务器应将它们带到登录屏幕。
启动时的配置 - 用户存储的 AspNetIdentity
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 TenantTokenRequestValidator : ICustomTokenRequestValidator
{
HttpContext _context;
IClientService _clientService;
public TenantTokenRequestValidator(IHttpContextAccessor contextAccessor, IClientService clientService)
{
_context = contextAccessor.HttpContext;
_clientService = clientService;
}
public Task ValidateAsync(CustomTokenRequestValidationContext context)
{
if (!context.Result.IsError)
{
//AuthorizationCode authorization_code
if (context.Result.ValidatedRequest.UserName!=null &&
!_clientService.IsValidUser(context.Result.ValidatedRequest.Client.ClientId,context.Result.ValidatedRequest.UserName))
{
context.Result.IsError = true;
context.Result.Error = "UnauthorizedUser";
}
}
return Task.CompletedTask;
}
}
租户授权请求验证程序 - 验证客户端和租户
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"}}
};
}
我正在使用上述方法验证客户端和租户以及客户端和用户。但是,无法实现基于租户的cookie,因此不同的登录名将使用不同的cookie在同一个浏览器会话上工作。Saaskit似乎不能很好地与aspnet core 2.0配合使用,找不到使用finbuckle的方法。
问题 - 如何使用租户设置 cookie 名称? 根据上下文 ACR 值从请求解析。 这种方法有效吗?
我们最终向用户帐户添加了一堆额外的客户端特定声明,并根据传入的声明设置授权策略。
例如-
API 资源希望根据令牌中的范围限制访问,这对于客户端验证很好,对于用户验证,它会在令牌中查找特定声明并提供访问权限。
使用上述方法,我们必须维护通过 UI 的用户的声明,对于没有用户访问服务器到服务器的其他客户端,维护客户端声明。
虽然这不是最好的方法,但这解决了我们当前的需求。
我们这样做的方法是,您需要在启动中为每个租户创建多个 AddCookie,并具有自己的方案名称。
然后在 ICustomAuthorizeRequestValidator 中,您将方案名称设置为与您为租户创建的方案相同(因此您可能必须定义一种通用格式,例如:Cookies-MyTenantId1 或 Cookies-MyTenantId2(。这样,将为每个租户创建不同的 Cookie。