Всегда вводите учетные данные без «prompt=login» в IdentityServer4

Это похоже на IdentityServer4 Заставить пользователя повторно ввести учетные данные, но в решении говорится использовать строку запроса prompt=login в URL-адресе /authorize, что работает, но также позволяет хитрым пользователям удалить ее. Кроме того, поскольку я не использую .AddOpenIdConnect(), предложение использовать OnRedirectToIdentityProvider ко мне не относится.

Итак, как мы можем заставить пользователя всегда вводить учетные данные, не полагаясь на prompt=login в строке запроса?


Вот моя базовая настройка IdentityServer4:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    var builder = services.AddIdentityServer()
        .AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryApiResources(Config.GetApis())
        .AddInMemoryClients(Config.GetClients());

    builder.AddDeveloperSigningCredential();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseHttpsRedirection();
    app.UseFileServer();
    app.UseIdentityServer();
    app.UseMvc();
}

Где на моей странице входа есть только кнопки «ОК» и «Отмена» (мне все равно, какой пользователь входит в систему, только эта аутентификация была в порядке или нет), а контроллер делает следующее, когда он аутентифицирует пользователя:

public async Task<IActionResult> Post(AuthenticateViewModel model, string button)
{
    var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

    if (button == "authCancel")
    {
        if (context != null)
        {
            await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);
            return Redirect(model.ReturnUrl);
        }

        return Redirect("~/");
    }

    if (button == "authOk" && ModelState.IsValid)
    {
        if (context != null)
        {
            await _events.RaiseAsync(new UserLoginSuccessEvent("provider", "userId", "subjectId", "name"));
            await HttpContext.SignInAsync("subject", "name", new AuthenticationProperties());
            return Redirect(model.ReturnUrl);
        }
    }

    return Redirect("~/");
}

Это довольно просто: просто переопределите схему файлов cookie по умолчанию, и пользователям всегда придется вводить учетные данные, несмотря на взлом URL-адресов.

Vidmantas Blazevicius 27.05.2019 18:35

Звучит неплохо. Хотите привести пример?

GTHvidsten 27.05.2019 18:39
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
2 451
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы должны иметь возможность добиться желаемого поведения, переопределив схему файлов cookie по умолчанию, которая AddIdentityServer() регистрируется внутри:

services.AddIdentityServer()...

services.AddAuthentication("CustomScheme")
    .AddCookie("CustomScheme", options =>
    {
        options.ExpireTimeSpan = ...;
    });

Убедитесь, что вы добавили схему переопределения после AddIdentityServer(), последовательность здесь важна из-за того, как работает ASP.Net Core DI.

Спасибо. Похоже, это основано на истечении срока действия файлов cookie. Каких значений обычно достаточно? Я предполагаю, что 0 секунд слишком мало, и пользователь уже снова выйдет из системы на auhorize/callback, а 10 секунд позволяют быстрым пользователям повторить попытку до истечения срока действия.

GTHvidsten 27.05.2019 19:16

Просто выберите что-то разумное, подходящее для вашей бизнес-проблемы, чего я не могу посоветовать. Я использовал истечение нескольких минут для аналогичного требования, как у вас в прошлом.

Vidmantas Blazevicius 27.05.2019 20:00

Я попробовал это и вижу в журнале следующие сообщения: CustomScheme was not authenticated. Failure message: Ticket expired, даже по истечении нескольких минут. Есть идеи, почему?

GTHvidsten 28.05.2019 14:14

Кажется, что это появляется много раз, когда вызывается authorize (вероятно, чтобы проверить, вошел ли пользователь в систему), но не после того, как пользователь прошел аутентификацию. Однако кажется немного ненужным заполнять журнал многими из этих сообщений журнала. Какие-либо предложения?

GTHvidsten 28.05.2019 14:29

Попробуйте 10 минут (из-за перекоса часов) и дайте файлу cookie какое-то пользовательское имя и проверьте, сохраняется ли правильный файл cookie при входе пользователя в систему.

Vidmantas Blazevicius 28.05.2019 15:02
Ответ принят как подходящий

Вариант может заключаться в том, чтобы придерживаться prompt=login для всех запросов или на основе некоторых настроек клиента или заголовка http.

Легко заглянуть в валидатор запросов по умолчанию и реализовать свою настройку следующим образом:

public class YourCustomAuthorizeRequestValidator:ICustomAuthorizeRequestValidator
{
  public Task ValidateAsync(CustomAuthorizeRequestValidationContext context)
  {
    var request = context.Result.ValidatedRequest;    
    if (string.IsNullOrWhiteSpace(request.Raw["prompted"]))
    {
      request.Raw.Add("prompted", "true");
      request.PromptMode = OidcConstants.PromptModes.Login;
    }
    else if (request.Subject.IsAuthenticated())
    {
      request.PromptMode = OidcConstants.PromptModes.None;
    }
    return Task.CompletedTask;
  }
}

а затем при запуске Identityserver:

services.AddIdentityServer()
  .AddCustomAuthorizeRequestValidator<YourCustomAuthorizeRequestValidator>();

Я попытался добавить пользовательский ICustomAuthorizeRequestValidator из вашего примера, и если он должен принудительно входить в систему при каждом запросе на authorize, это не совсем работает. Я звоню authorize и он первый раз просит логин. Во второй раз он не запрашивает логин и переходит прямо к redirect_uri.

GTHvidsten 28.05.2019 11:54

Я пытался закомментировать условие, но оно никогда не продолжается после /authorize. Я получаю экран входа в систему, нажимаю, чтобы войти, затем я снова получаю экран входа (повторяю до бесконечности)

GTHvidsten 28.05.2019 12:19

Вероятно, вам следует обновить свой код, чтобы использовать string.IsNullOrEmpty() вместо .IsMissing(), но в остальном это, кажется, делает именно то, что я хочу. Спасибо :)

GTHvidsten 28.05.2019 19:22
IsMissing() - это просто удобная оболочка return string.IsNullOrWhiteSpace(value);, но, возможно, я украл ее из внутренностей Identityserver... тогда изменится
d_f 28.05.2019 19:43

Другие вопросы по теме