Как сделать пользовательские утверждения доступными в запросах API

У меня есть решение, состоящее из:

  • ASP.NET Core 2.1 с IdentityServer4 поверх ASP.NET Identity Core.
  • Веб-API ASP.NET Core 2.1 настроен на использование IdentityServer в качестве поставщика проверки подлинности.
  • Веб-приложение React SPA, использующее oidc-client библиотеку javascript.

Когда я создаю новых пользователей, я устанавливаю некоторые пользовательские утверждения, которые сохраняются в таблице AspNetUserClaims, которая выглядит следующим образом: введите здесь описание изображения

Затем, в моем проекте API, внутри контроллера я хочу получить эти утверждения пользователя, прошедшего проверку подлинности.
Я ожидал, что this.User.Claims получит их, но вместо этого он возвращает следующее, которое, похоже, является утверждениями, связанными с клиентом. приложение, а не пользователь.

введите здесь описание изображения

Как я могу получить доступ к этим пользовательским утверждениям (address, location, tenant_role) из контроллера внутри проекта веб-API?
Имейте в виду, что проект API не имеет доступа к классу UserManager или чему-либо, связанному с ASP.NET Identity Core.


person empz    schedule 10.12.2018    source источник
comment
Используете ли вы токены доступа? Если это так, вы можете закодировать пользовательские утверждения в токен, который должен неявно разрешить вам доступ к ним через this.User.Claims. В противном случае вам нужно будет создать метод доступа к UserManager.   -  person Chris Pickford    schedule 10.12.2018
comment
Да, я использую токен доступа (через заголовок Authorization: Bearer xxxx). Не уверен, как мне кодировать утверждения в токен в IdentityServer. Любой пост/ресурс, который объясняет, как это сделать?   -  person empz    schedule 10.12.2018


Ответы (4)


Итак, я заказываю, чтобы моя пользовательская претензия была доступна в каждом запросе API. Мне нужно было сделать следующее при настройке ApiResource при запуске IdentityServer.

//Config.cs
public static IEnumerable<ApiResource> GetApiResources()
{
    ApiResource apiResource = new ApiResource("api1", "DG Analytics Portal API")
    {
        UserClaims =
        {
            JwtClaimTypes.Name,
            JwtClaimTypes.Email,
            AnalyticsConstants.TenantRoleClaim // my custom claim key/name
        }
    };

    return new List<ApiResource>
    {
        apiResource
    };
}

Этот метод передается services.AddInMemoryApiResources (или любому другому методу хранения, который вы используете)

IIdentityServerBuilder builder = services
                .AddIdentityServer(options =>
                {
                    options.Events.RaiseErrorEvents = true;
                    options.Events.RaiseInformationEvents = true;
                    options.Events.RaiseFailureEvents = true;
                    options.Events.RaiseSuccessEvents = true;
                })
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryApiResources(Config.GetApiResources()) // here
                .AddInMemoryClients(Config.GetClients())
                .AddAspNetIdentity<ApplicationUser>();

При такой настройке всякий раз, когда происходит попадание в конечную точку API, мое пользовательское требование TenantRole присутствует, поэтому я могу просто выполнить User.FindFirst(AnalyticsConstants.TenantRoleClaim), чтобы получить его.

person empz    schedule 10.12.2018
comment
Спасибо!! Я искал это в течение долгого времени! - person M B; 28.05.2019

Вам нужно будет определить ресурсы и области идентификации а-ля:

http://docs.identityserver.io/en/latest/topics/resources.html

Затем убедитесь, что они доступны вашей реализации IProfileService или IClaimsService на вашем сервере идентификации:

http://docs.identityserver.io/en/latest/reference/profileservice.html

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

person mackie    schedule 10.12.2018
comment
Я не мог заставить это работать, но я нашел гораздо более простое решение. Не уверен, почему никто не указал это. Смотрите мой ответ. - person empz; 10.12.2018

Я написал этот расширитель для использования в MVC 5, но, поскольку он использует контекст http и системную безопасность (а не диспетчер пользователей или идентификацию), я предполагаю, что внутренности этого будут работать на MVC6.

public static bool UserHasSpecificClaim(this HtmlHelper h, string claimType, string claimValue)
{
    // get user claims
    var user = HttpContext.Current.User as System.Security.Claims.ClaimsPrincipal;

    if (user != null)
    {
        // Get the specific claim if any
        return user.Claims.Any(c => c.Type == claimType && c.Value == claimValue);
    }

    return false;
}
person pixelda    schedule 10.12.2018
comment
Это просто вспомогательный метод. Заявления, которые я ищу, отсутствуют в ClaimsPrincipal.Claims. - person empz; 10.12.2018

Вы можете использовать ClaimsPrincipal.FindFirst() для доступа к персонализированным заявкам.

Документ: https://docs.microsoft.com/en-us/dotnet/api/system.security.claims.claimsprincipal.findfirst?view=netcore-2.1

Пример: User.FindFirst("your_claim_key").Value

person wannadream    schedule 10.12.2018
comment
Это не работает. Проблема не в том, как получить к ним доступ, проблема в том, что утверждения отсутствуют в токене доступа. На стороне IdentityServer4 должно быть что-то, чтобы указать ему включить эти утверждения в токен. - person empz; 10.12.2018
comment
Я понимаю. Вот быстрый пример: korzh.com/ блоги/net-tricks/. - person wannadream; 10.12.2018