Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 密码流的IdentityServer4客户端不包括访问令牌中的TestUser声明_C#_Asp.net Core_Oauth 2.0_Identityserver4_Openid - Fatal编程技术网

C# 密码流的IdentityServer4客户端不包括访问令牌中的TestUser声明

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(新[] {

我正在尝试使用IdentityServer4中的(遗留)资源所有者密码流创建一个沙盒应用程序。我用以下软件包建立了一个全新的ASP.NET Core 3项目:


我正在使用以下启动部分:

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);