IdentityServer4 аутентификация по внешнему API - PullRequest
0 голосов
/ 30 марта 2020

У нас есть требование для аутентификации пользователей в IdentityServer4 по внешнему API. Сценарий работает следующим образом:

  1. Пользователь посещает клиентское приложение Javascript и нажимает кнопку входа в систему, чтобы перенаправить на страницу входа в IdentityServer (точно такой же клиент, как указано в документации здесь
  2. Пользователь вводит свое имя пользователя (адрес электронной почты) и пароль

  3. IdentityServer4 подключается к внешнему API для проверки учетных данных

  4. Пользователь перенаправляется обратно в приложение JavaScript

Вышеописанный процесс отлично работает при использовании TestUsers, представленных в QuickStarts. Однако при использовании API страница входа в систему сбрасывается и не перенаправляет пользователя обратно на клиент JavaScript. Единственное изменение - это приведенный ниже код и пользовательская реализация IProfileService.

Ниже приведен пользовательский код в действии входа в систему (отображается только соответствующая часть):

            var apiClient = _httpClientFactory.CreateClient("API");
            var request = new HttpRequestMessage(HttpMethod.Post, "/api/auth");

            var loginModel = new LoginModel
            {
                Email = model.Email,
                Password = model.Password
            };
            var content = new StringContent(JsonConvert.SerializeObject(loginModel), 
                                                Encoding.UTF8, "application/json");

            request.Content = content;

            HttpResponseMessage result = await apiClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);

            var loginStatus = JsonConvert.DeserializeObject<ApiLoginStatus>(
                                    await result.Content.ReadAsStringAsync());

            if (loginStatus.LoginSuccess)
            {
                await _events.RaiseAsync(new UserLoginSuccessEvent(model.Email, model.Email, loginStatus.Name, clientId: context?.ClientId));

                AuthenticationProperties props = null;
                if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                {
                    props = new AuthenticationProperties
                    {
                        IsPersistent = true,
                        ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                    };
                };

                var user = new IdentityServerUser(loginStatus.SubjectId)
                {
                    DisplayName = loginStatus.Name
                };

                await HttpContext.SignInAsync(user, props);
                if (context != null)
                {
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        return View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
                    }

                    return Redirect(model.ReturnUrl);
                }

Код фактически соответствует пути возврата View (), но по какой-то причине он сбрасывается, и страница входа снова отображается.

Код в Startu p.cs:

var builder = services.AddIdentityServer()
            .AddInMemoryIdentityResources(Config.Ids)
            .AddInMemoryApiResources(Config.Apis)
            .AddInMemoryClients(Config.Clients) 
            .AddProfileService<ProfileService>()
            .AddDeveloperSigningCredential();

Код в ProfileService.cs:

public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
    var profile = await GetUserProfile(context.Subject.GetSubjectId());

    var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Email, profile.Email),
            new Claim(ClaimTypes.Name, profile.Name)
        };

    context.IssuedClaims.AddRange(claims);
}

public async Task IsActiveAsync(IsActiveContext context)
{
    var profile = await GetUserProfile(context.Subject.GetSubjectId());
    context.IsActive = (profile != null);
}

В Интернете есть несколько источников, показывающих, как использовать пользовательское хранилище для аутентификации, но все они, похоже, используют ResourceOwnerPasswordValidator. Если бы кто-то мог указать на то, чего здесь не хватает, это очень помогло бы. Спасибо.

1 Ответ

0 голосов
/ 31 марта 2020

Таким образом, проблема оказалась очень простой. Мы пропустили удаление строки builder.AddTestUsers (TestUsers.Users) при настройке IdentityServer в Startup.cs.

Глядя на код здесь , оказалось, что эта строка переопределяет наш сервис профилей с сервисом профилей тестовых пользователей. Удаление этой строки решило проблему.

...