密码流的 IdentityServer4 客户端不包括访问令牌中的 TestUser 声明
IdentityServer4 client for Password Flow not including TestUser claims in access token
我正在尝试使用 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") },
},
})
然后我提供一个调用 /connect/token
端点的静态 index.html
文件,如下所示:
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
}),
});
但它 returns 我 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"
]
}
我在 access_token
.
中缺少作为顶级条目的电子邮件、角色等
在挖掘源代码时,我看到 the ProfileService for TestUsers should add all requested claims to the token via an extension method。我在谷歌搜索我的问题时发现的大多数问题要么是我已经做过的(或尝试过的,见下文),要么是关于其他边缘情况的。
许多其他线程也导致Dominick Baier's post on roles,但问题是API方无法识别该角色。 我的问题是 role
根本不包含在令牌中。
我尝试过的:
- 在各个地方
"role"
和 JwtClaimTypes.Role
之间切换。
- 有无
IdentityResources
- 挖掘 IDS4 代码库以找到其背后的逻辑
关于 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 流?
我错过了什么?我 真的 需要 create a custom ProfileService
to add all these claims? I really felt the default ProfileService
for TestUser
s 应该已经这样做了吗??
我最终得到了以下结果(不确定它是解决方案还是解决方法),因为它对未来的访问者有什么价值:
new ApiResource("foo-api")
{
Scopes =
{
new Scope("foo-api.with.roles", new[] { "role" }),
}
}
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", "foo-api.with.roles" },
}
new TestUser
{
SubjectId = "EFG-456",
Username = "mary",
Password = "secret",
Claims = { new Claim("role", "editor") },
}
然后像这样检索令牌:
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": "mary",
"password": "secret",
}),
});
const json = await response.json();
console.log(json);
您应该能够 clone my sample-asp-net-core-auth-policies
repository 和 运行 它开箱即用,以在工作中看到它。
我正在尝试使用 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") },
},
})
然后我提供一个调用 /connect/token
端点的静态 index.html
文件,如下所示:
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
}),
});
但它 returns 我 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"
]
}
我在 access_token
.
在挖掘源代码时,我看到 the ProfileService for TestUsers should add all requested claims to the token via an extension method。我在谷歌搜索我的问题时发现的大多数问题要么是我已经做过的(或尝试过的,见下文),要么是关于其他边缘情况的。
许多其他线程也导致Dominick Baier's post on roles,但问题是API方无法识别该角色。 我的问题是 role
根本不包含在令牌中。
我尝试过的:
- 在各个地方
"role"
和JwtClaimTypes.Role
之间切换。 - 有无
IdentityResources
- 挖掘 IDS4 代码库以找到其背后的逻辑
关于 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 流?
我错过了什么?我 真的 需要 create a custom ProfileService
to add all these claims? I really felt the default ProfileService
for TestUser
s 应该已经这样做了吗??
我最终得到了以下结果(不确定它是解决方案还是解决方法),因为它对未来的访问者有什么价值:
new ApiResource("foo-api")
{
Scopes =
{
new Scope("foo-api.with.roles", new[] { "role" }),
}
}
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", "foo-api.with.roles" },
}
new TestUser
{
SubjectId = "EFG-456",
Username = "mary",
Password = "secret",
Claims = { new Claim("role", "editor") },
}
然后像这样检索令牌:
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": "mary",
"password": "secret",
}),
});
const json = await response.json();
console.log(json);
您应该能够 clone my sample-asp-net-core-auth-policies
repository 和 运行 它开箱即用,以在工作中看到它。