Авторизация Aps .net IdentityServer4

Я использую IdentityServer4 с идентификатором asp .net в качестве точки аутентификации. Мои API/WebApps вызывают сервер идентификации для получения токена доступа.

Теперь, как авторизовать использование перед каким-либо действием или внутри действия в моем контроллере API/приложения?

Я могу добавить роли для токена доступа, а затем в контроллере (в веб-API/веб-приложении) использовать AuthorizeAttribute и проверить, является ли пользователь IsInRole.

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

Я хотел бы спрашивать сервер идентификации о роли (ролях) пользователя каждый раз, когда мне нужно разрешить ему какое-либо действие (особенно для таких действий, как изменение/удаление некоторых данных).

Вопрос как? Или что я должен искать?




Ответы (1)


Итак, здесь есть несколько возможных решений:

  • Вызовите конечную точку OIDC UserInfo, чтобы получать обновленные утверждения пользователей по каждому запросу.
  • Уменьшите время жизни файлов cookie, чтобы чаще автоматически обновлять информацию о пользователе.
  • Реализуйте пользовательскую конечную точку на IdentityServer, чтобы она могла публиковать информацию об изменении профиля в списке подписанных клиентов (например, в вашем веб-приложении).
  • Заставить IdentityServer принудительно выполнять единый выход при изменении данных профиля пользователя.

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

Вызов веб-приложением конечной точки UserInfo при каждом запросе является следующим простым (см. пример ниже), но имеет худшие последствия для производительности. Каждый запрос будет производить круговое путешествие к IdentityServer.

Модель конечной точки/подписчика будет иметь наименьшую нагрузку на производительность. Запросы UserInfo к IdentityServer будут происходить ТОЛЬКО тогда, когда информация о профиле пользователя действительно изменилась. Это было бы немного сложнее реализовать:

  1. В вашем проекте IdentityServer вам нужно будет изменить изменения в данных профиля и опубликовать http-сообщение в своем веб-приложении. Сообщение может просто содержать идентификатор измененного пользователя. Это сообщение должно быть каким-то образом аутентифицировано, чтобы злоумышленники не могли аннулировать законные пользовательские сеансы. Для этого вы можете включить токен носителя ClientCredentials.
  2. Ваше веб-приложение должно будет получить и аутентифицировать сообщение. Необходимо будет сохранить измененный идентификатор пользователя где-нибудь, доступном для делегата OnValidatePrincipal (скорее всего, через службу в контейнере DI)
  3. Затем делегат Cookie OnValidatePrincipal внедрит эту локальную службу, чтобы проверить, изменилась ли информация о пользователе перед проверкой принципала.

Примеры кода

Получайте обновленную информацию о пользователе с конечной точки при каждом вызове

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = "NameOfYourCookieAuthSchemeHere",
    Events = new CookieAuthenticationEvents()
    {
        OnValidatePrincipal = async context =>
        {
            // Get updated UserInfo from IdentityServer
            var accessToken = context.Principal.Claims.FirstOrDefault(c => c.Type == "access_token").Value;
            var userInfoClient = new UserInfoClient("https://{IdentityServerUrlGoesHere}");
            var userInfoResponse = await userInfoClient.GetAsync(accessToken);

            // Invalidate Principal if Error Response
            if (userInfoResponse.IsError)
            {
                context.RejectPrincipal();
                await context.HttpContext.Authentication.SignOutAsync("NameOfYourCookieAuthSchemeHere");
            }
            else
            {
                // Check if claims changed
                var claimsChanged = userInfoResponse.Claims.Except(context.Principal.Claims).Any();
                if (claimsChanged)
                {
                    // Update claims and replace principal
                    var newIdentity = context.Principal.Identity as ClaimsIdentity;
                    newIdentity.AddClaims(userInfoResponse.Claims);
                    var updatedPrincipal = new ClaimsPrincipal();
                    context.ReplacePrincipal(updatedPrincipal);
                    context.ShouldRenew = true;
                }
            }
        }
    }
});

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

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = "NameOfYourCookieAuthSchemeHere",
    Events = new CookieAuthenticationEvents()
    {
        OnValidatePrincipal = async context =>
        {
            // Get User ID
            var userId = context.Principal.Claims.FirstOrDefault(c => c.Type == "UserIdClaimTypeHere");

            var userChangedService = context.HttpContext.RequestServices.GetRequiredService<IUserChangedService>();
            var userChanged = await userChangedService.HasUserChanged(userId);

            if (userChanged)
            {
                // Make call to UserInfoEndpoint and update ClaimsPrincipal here. See example above for details
            }
        }
    }
});

В основных документах asp.net также есть пример этого, за исключением работы с локальной базой данных. Подход к методу OnValidatePrincipal такой же: https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie#reacting-to-back-end-changes

Надеюсь это поможет!

person kg743    schedule 12.05.2017