Клиент IdentityServer4 для потока паролей, не включающий утверждения TestUser в токен доступа - PullRequest
0 голосов
/ 04 мая 2020

Я пытаюсь создать приложение-песочницу, используя (устаревший) поток пароля владельца ресурса в IdentityServer4. Я настроил совершенно новый ASP. NET Core 3 проект с этими пакетами:

<PackageReference Include="IdentityServer4" Version="3.1.3" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />

Я использую следующие разделы запуска:

services.AddIdentityServer()
    .AddDeveloperSigningCredential()
    .AddInMemoryApiResources(new[] { new ApiResource("foo-api") })
    .AddInMemoryIdentityResources(new[]
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        new IdentityResources.Email(),
        new IdentityResource("role", new[] { JwtClaimTypes.Role }),
    })
    .AddInMemoryClients(new[]
    {
        new Client
        {
            // Don't use RPO if you can prevent it. We use it here
            // because it's the easiest way to demo with users.
            ClientId = "legacy-rpo",
            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
            AllowAccessTokensViaBrowser = false,
            RequireClientSecret = false,
            AllowedScopes = { "foo-api", "openid", "profile", "email", "role" },

        },
    })
    .AddTestUsers(new List<TestUser>
    {
        new TestUser
        {
            SubjectId = "ABC-123",
            Username = "john",
            Password = "secret",
            Claims = new[]
            {
                new Claim(JwtClaimTypes.Role, "user"),
                new Claim(JwtClaimTypes.Email, "john@example.org"),
                new Claim("x-domain", "foo") },
        },
    })

И затем я передаю файл stati c index.html, который вызывает конечную точку /connect/token следующим образом:

const response = await fetch("/connect/token", {
    method: "POST",
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
    },
    body: new URLSearchParams({
        "grant_type": "password",
        "client_id": "legacy-rpo",
        "username": "john",
        "password": "secret",
        // scope omitted should net *all* scopes in IDS4
    }),
});

Но он возвращает мне access_token, который (декодированный) выглядит следующим образом :

{
  "nbf": 1588582642,
  "exp": 1588586242,
  "iss": "https://localhost:5001",
  "aud": "foo-api",
  "client_id": "legacy-rpo",
  "sub": "ABC-123",
  "auth_time": 1588582642,
  "idp": "local",
  "scope": [
    "email",
    "openid",
    "profile",
    "role",
    "foo-api"
  ],
  "amr": [
    "pwd"
  ]
}

Мне не хватает электронной почты, роли и т. Д. c. в качестве записей верхнего уровня в access_token.

При копании в исходном коде я вижу, что ProfileService для TestUsers должен добавить все запрошенные утверждения в токен с помощью метод расширения . Большинство вопросов, которые я нашел при поиске своей проблемы, или делают то, что я уже делаю (или пытался, см. Ниже), или касаются других крайних случаев.

Многие другие темы также приводят к посту Доминика Байера о ролях , но проблема в том, что сторона API не распознает роль. Моя проблема в том, что role вообще не входит в токен.

Что я пробовал:

  • Переключение между "role" и JwtClaimTypes.Role в разных местах.
  • С и без IdentityResources
  • Копая базу кодов IDS4, чтобы найти логи c за этим

Сноска о ProfileService

Я пытался добавить это:

public class ProfileService : TestUserProfileService
{
    public ProfileService(TestUserStore users, ILogger<TestUserProfileService> logger) 
        : base(users, logger)
    { }

    public override Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var role = context.Subject.FindFirst(ClaimTypes.Role);
        context.IssuedClaims.Add(role);
        return base.GetProfileDataAsync(context);
    }

    public override Task IsActiveAsync(IsActiveContext context)
    {
        return base.IsActiveAsync(context);
    }
}

в AddIdentityServer() цепочку строителя:

.AddProfileService<ProfileService>()

, но метод GetProfileDataAsync(...) не используется вообще, точка останова не срабатывает. Таким образом, можно предположить, что значение по умолчанию TestUserProfileService также никогда не будет изменено, что объясняет отсутствие утверждений в моих токенах.

Возможно, это не поддерживается в потоке паролей, возможно, потому что это OAuth2, а не поток OpenID Connect ?


Чего мне не хватает? Мне действительно нужно создать пользовательский ProfileService, чтобы добавить все эти претензии? Я действительно чувствовал, что по умолчанию ProfileService для TestUser s должен сделать это уже ??

...