Я пытаюсь создать приложение-песочницу, используя (устаревший) поток пароля владельца ресурса в 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 должен сделать это уже ??