C# 密码流的IdentityServer4客户端不包括访问令牌中的TestUser声明
我正在尝试使用IdentityServer4中的(遗留)资源所有者密码流创建一个沙盒应用程序。我用以下软件包建立了一个全新的ASP.NET Core 3项目:C# 密码流的IdentityServer4客户端不包括访问令牌中的TestUser声明,c#,asp.net-core,oauth-2.0,identityserver4,openid,C#,Asp.net Core,Oauth 2.0,Identityserver4,Openid,我正在尝试使用IdentityServer4中的(遗留)资源所有者密码流创建一个沙盒应用程序。我用以下软件包建立了一个全新的ASP.NET Core 3项目: 我正在使用以下启动部分: services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryApiResources(新[]{new ApiResource(“foo api”)}) .AddInMemoryIdentityResources(新[] {
我正在使用以下启动部分:
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(新[]{new ApiResource(“foo api”)})
.AddInMemoryIdentityResources(新[]
{
新标识资源.OpenId(),
新标识资源.Profile(),
新标识资源.Email(),
新标识资源(“角色”,新[]{JwtClaimTypes.role}),
})
.AddInMemoryClients(新[]
{
新客户
{
//如果可以防止,请不要使用RPO。我们在这里使用它
//因为这是向用户演示的最简单的方法。
ClientId=“旧版rpo”,
AllowedGrantTypes=GrantTypes.ResourceOwnerPassword,
AllowAccessTokensViaBrowser=false,
RequireClientSecret=false,
AllowedScopes={“fooapi”、“openid”、“profile”、“email”、“role”},
},
})
.AddTestUsers(新列表
{
新测试用户
{
SubjectId=“ABC-123”,
用户名=“约翰”,
Password=“secret”,
索赔=新[]
{
新声明(JwtClaimTypes.Role,“用户”),
新索赔(JwtClaimTypes.Email,“john@example.org"),
新索赔(“x域”、“foo”)},
},
})
然后我提供一个静态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": "mary",
"password": "secret",
}),
});
const json = await response.json();
console.log(json);
const response=wait fetch(“/connect/token”{
方法:“张贴”,
标题:{
“内容类型”:“应用程序/x-www-form-urlencoded;字符集=UTF-8”,
},
正文:新URLSearchParams({
“授权类型”:“密码”,
“客户id”:“传统rpo”,
“用户名”:“约翰”,
“密码”:“秘密”,
//省略的作用域应为IDS4中的净*所有*作用域
}),
});
但它会返回一个access_令牌,该令牌(已解码)如下所示:
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);
{
“nbf”:1588582642,
“经验”:1588586242,
“国际空间站”:https://localhost:5001",
“aud”:“foo api”,
“客户id”:“传统rpo”,
“sub”:“ABC-123”,
“授权时间”:1588582642,
“idp”:“本地”,
“范围”:[
“电子邮件”,
“openid”,
“个人资料”,
“角色”,
“富api”
],
“amr”:[
“pwd”
]
}
我在access\u令牌中缺少作为顶级条目的电子邮件、角色等
在深入研究源代码时,我发现应该通过将所有请求的声明添加到令牌中。我在谷歌搜索问题时发现的大多数问题要么是我已经做过的(或尝试过的,见下文),要么是关于其他边缘案例的
许多其他线程也会导致此问题,但问题是API端不识别此角色我的问题是,角色
根本不包含在令牌中。
我所尝试的:
- 在
和“角色”
JwtClaimTypes之间切换。角色在不同的位置
- 有和没有
IdentityResources
- 挖掘IDS4代码库以找到其背后的逻辑
关于
档案服务的脚注
我尝试添加以下内容:
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);
}
}
但是根本没有命中GetProfileDataAsync(…)
方法,没有断点触发器。因此,这意味着默认的TestUserProfileService
也不会被命中,从而解释了我的令牌中缺少声明的原因
这在密码流中不受支持,可能是因为它是OAuth2而不是OpenID连接流吗
我错过了什么?我真的需要添加所有这些声明吗?我真的觉得应该已经这样做了???我最终得出以下结论(不确定这是一个解决方案还是一个解决办法),这对未来的访问者来说是值得的:
new ApiResource("foo-api")
{
Scopes =
{
new Scope("foo-api.with.roles", new[] { "role" }),
}
}
然后像这样检索令牌:
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);
您应该能够开箱即用地运行它,以便在工作时看到这一点。以前在
客户机中有一个设置,它总是围绕运行,如cludueserclaimsindotoken
或类似的设置。。。如果没有它,默认情况下您将无法在令牌中获得声明,因此需要立即调用identity server 4中的/userinfo
端点来获取该数据。嗯,我想我已经尝试过了,并且可能会再次这样做,以再次检查它是否解决了问题。不过,该设置确实讨论了IdToken,我希望声明位于访问令牌中。-不知何故,我使用EF Core和ASP.NET Identity的真实应用程序确实“神奇地”包含了角色,所以也许我应该检查他们的源代码…我可能有一些解决方案的开始,但会推迟发布,因为没有答案的问题会得到更多的关注,我希望看到其他人的见解…对于资源所有者流,您可以通过IResourceOwnerPasswordValidator
interface@CeylanMumunKocabaş我找到了一种获得我需要的东西的方法,不确定这是一种解决方案还是一种变通办法。我已经把它作为一个答案分享了。
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);