IdentityServer4 обеспечивает работу единого входа вместе с функциями STS. SSO работает, как только клиенты проверены согласно OAuth OpenId Connect. Таким образом, пользователи, если личность основана на 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>();
Валидатор запроса Tenant Token - проверка пользователя и клиента
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 2.0, не найдя выхода с помощью finbuckle.
вопрос - Как установить имя куки с арендатором? разрешение из запроса на основе значений acr контекста. этот подход работает?