Как получить доступ к пользовательской заявке в качестве основного приложения pnet, авторизованного с использованием Identity Server - PullRequest
0 голосов
/ 11 апреля 2020

Я следую шаблону быстрого запуска Identity Server и пытаюсь настроить следующий

  • Identity Server в качестве pnet основного приложения
  • Mvc клиента, который аутентифицируется в is4 а также вызывает клиента webapi, который является защищенным ресурсом API.

В ApplicationUser есть дополнительный столбец, который я добавляю в заявки из ProfileService, например:

        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);
            if (user == null)
                return;

            var principal = await _claimsFactory.CreateAsync(user);
            if (principal == null)
                return;

            var claims = principal.Claims.ToList();

            claims.Add(new Claim(type: "clientidentifier", user.ClientId ?? string.Empty));

            // ... add roles and so on

            context.IssuedClaims = claims;
        }

И, наконец, вот конфигурация в методе Mvc Клиентское приложение ConfigureServices:

            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            }).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddOpenIdConnect("oidc", options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;

                options.ClientId = "mvc";
                options.ClientSecret = "mvc-secret";
                options.ResponseType = "code";

                options.SaveTokens = true;

                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Scope.Add("offline_access");

                options.Scope.Add("api1");

                options.GetClaimsFromUserInfoEndpoint = true;

                options.ClaimActions.MapUniqueJsonKey("clientidentifier", "clientidentifier");
            });

Если для GetClaimsFromUserInfoEndpoint установлено значение true, я могу получить доступ к пользовательской заявке в User.Identity, но это приводит к 2 вызывает ProfileService.

Если я удаляю или задаю значение false, то это утверждение все еще является частью access_token, но не частью id_token, и тогда я не могу получить доступ к этому заданному утверждению c из контекста User .

Есть ли лучший способ, которым я могу получить доступ к этой заявке от Принципала пользователя, не приводя к 2 вызовам (как сейчас)? или, возможно, чтение access_token из контекста и обновление утверждений пользователя после получения токена?

спасибо :)

Ответы [ 3 ]

0 голосов
/ 13 апреля 2020

Оказывается, что у объекта Client на сервере идентификации есть это свойство, которое выполняет эту работу:

        //
        // Summary:
        //     When requesting both an id token and access token, should the user claims always
        //     be added to the id token instead of requring the client to use the userinfo endpoint.
        //     Defaults to false.
        public bool AlwaysIncludeUserClaimsInIdToken { get; set; }

Как объясняется в метаданных lib, для клиента значение true, тогда для клиенту go и повторному получению претензий от конечной точки

спасибо всем :)

0 голосов
/ 15 апреля 2020

Вот немного дополнительной информации по теме. По умолчанию IdentityServer не включает утверждения личности в токене идентификации. Это можно сделать, установив для параметра AlwaysIncludeUserClaimsInIdToken в конфигурации клиента значение true. Но это не рекомендуется. Исходный идентификационный токен возвращается из конечной точки авторизации через связь по переднему каналу либо через сообщение формы, либо через URI. Если он возвращается через URI и токен становится слишком большим, вы можете столкнуться с ограничениями длины URI, которые все еще зависят от браузера. Большинство современных браузеров не имеют проблем с длинными URI, но старые браузеры, такие как Inte rnet Explorer, могут это сделать. Это может или не может беспокоить вас. Похоже, мой проект похож на ваш. Удачи.

0 голосов
/ 11 апреля 2020

Я предполагаю, что вы передаете заголовок авторизации с токеном Bearer JWT при вызове API. Вы можете прочитать access_token из HttpContext в вашем контроллере API.

  var accessToken = await this.HttpContext.GetTokenAsync("access_token");
    var handler = new JwtSecurityTokenHandler();

    if (handler.ReadToken(accessToken) is JwtSecurityToken jt && (jsonToken.Claims.FirstOrDefault(claim => claim.Type == "sub") != null))
    {
        var subID = jt.Claims.FirstOrDefault(claim => claim.Type == "sub").Value;
    }

ПРИМЕЧАНИЕ: GetClaimsFromUserInfoEndpoint устанавливать не нужно явно.

...