Как повторно войти в систему в автоматическом режиме, используя аутентификацию IdentityServer4

Aug 20 2020

У нас есть решение, основанное на сторонней структуре ABP и ее многоуровневой архитектуре:

Мы используем Angular в качестве веб-интерфейса и IdentityServer4 для аутентификации пользователя. Итак, у нас запущено 2 хоста - хост HTTP API и хост IdentityServer, а что касается веб-интерфейса, он работает стандартным образом: поле входа, пользователь вводит учетные данные - вуаля.

Тем не менее, у нас есть специальная настройка, позволяющая использовать одно и то же имя для входа под другим клиентом. Список клиентов отображается в виде раскрывающегося списка в пользовательском интерфейсе, и мы хотели бы повторно войти в систему для пользователя с выбранным клиентом, а не для пользователя, вошедшего в систему в данный момент. Это должно выглядеть как простая перезагрузка страницы. Проблема в том, что у меня нет четкого понимания, как это реализовать. Я попытался использовать следующий вызов из уровня приложения, но он не работает (ошибка: «Для схемы Identity.Application» не зарегистрирован обработчик аутентификации ... », но я не знаю, как настроить конфигурация аутентификации на уровне приложения для работы с нашим IdentityServer):

    [HttpGet]
    public async Task<TenantDto> SwitchTenantForCurrentUser(Guid? tenantId)
    {
        var abxUser = await _abxUserRepository.FirstOrDefaultAsync(x => x.Login == CurrentUser.UserName && x.Tenant.AbpId == tenantId);

        if (abxUser == null)
            return null;

        using var _ = _abpCurrentTenant.Change(tenantId);

        var currentTenant = await _abxTenantRepository.FirstOrDefaultAsync(x => x.AbpId == _abpCurrentTenant.Id.Value);
        var identityUser = await _identityUserRepository.FindByNormalizedUserNameAsync(abxUser.Login.ToUpper());

        if (await _signInManager.CanSignInAsync(identityUser))
        {
            await _signInManager.SignOutAsync();
            await _signInManager.SignInAsync(identityUser, true);
        }

        return ObjectMapper.Map<Tenant, TenantDto>(currentTenant); // Not decided yet what to return, it depends on proper implementation
    }

Часть конфигурации от хоста Http API для аутентификации:

    private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(options =>
            {
                options.Authority = configuration["AuthServer:Authority"];
                options.RequireHttpsMetadata = true;
                options.ApiName = "CentralTools";
                options.JwtBackChannelHandler = new HttpClientHandler
                {
                    //TODO: use valid certificate in future and change the logic
                    ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
                };
            });

        context.Services.AddAbpIdentity().AddDefaultTokenProviders();

Ответы

1 Alexander Aug 26 2020 at 16:49

Миссия выполнена. Шаги:

  1. BACK-END: реализовать и зарегистрировать пользовательский валидатор типа гранта в проекте IdentityServer:

    SwitchToTenantGrantValidator: IdentityServer4.Validation.IExtensionGrantValidator

Короче говоря, ValidateAsync принимает данные аутентифицированного пользователя (его токен доступа, идентификатор клиента и т. Д.) И принимает решение, следует ли впустить пользователя. Метод записывает данные целевого клиента в объект результата контекста;

  1. FRONT-END: вызвать IdentityServer с заданным настраиваемым типом гранта, предоставив данные, необходимые для (1). Мы использовали Angular, поэтому мне пришлось расширить OAuthService для поддержки запроса настраиваемого типа гранта;

  2. Приведите все в порядок (если (2) прошло успешно) для отображения правильных данных в пользовательском интерфейсе: очистите старые состояния и т. Д.