C# 在没有自定义声明的情况下访问\u令牌,声明仍然从userinfo返回

C# 在没有自定义声明的情况下访问\u令牌,声明仍然从userinfo返回,c#,asp.net-core,identityserver4,C#,Asp.net Core,Identityserver4,Tl;dr:如何防止自定义声明出现在访问令牌中,并且仅在调用userinfo端点时才返回 我有一个IdentityServer4(使用authorization\u codegrant type),在第三方身份验证成功后,我可以从中获得有关用户的一些附加信息。我将这些存储为声明,将用户登录到IS4服务,并将这些声明添加到用户。声明连接到一个名为“custom”的标识资源范围 现在,当我检索访问令牌时,它不包含这些自定义声明,但它包含“自定义”范围。下一步是调用userinfo端点来获取这些自定义

Tl;dr:如何防止自定义声明出现在访问令牌中,并且仅在调用
userinfo
端点时才返回

我有一个IdentityServer4(使用
authorization\u code
grant type),在第三方身份验证成功后,我可以从中获得有关用户的一些附加信息。我将这些存储为声明,将用户登录到IS4服务,并将这些声明添加到用户。声明连接到一个名为“custom”的标识资源范围

现在,当我检索访问令牌时,它不包含这些自定义声明,但它包含“自定义”范围。下一步是调用
userinfo
端点来获取这些自定义声明。但是,默认情况下,对
userinfo
端点的调用不包括这些自定义声明

因此,我创建了一个
IProfileService
,将索赔复制到
IssuedClaims

public class ProfileService : IProfileService
{
    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
         List<Claim> claims = new List<Claim>();

        foreach (IdentityResource identityResource in context.RequestedResources.IdentityResources)
        {
            foreach (string userClaim in identityResource.UserClaims)
            {
                var claim = context.Subject.Claims.FirstOrDefault(c => c.Type == userClaim);
                if (claim != null)
                {
                    claims.Add(claim);
                }
            }
        }

        if (claims.Any())
        {
            context.IssuedClaims.AddRange(claims);
        }

        return Task.CompletedTask;
    }
}
public类ProfileService:IProfileService
{
公共任务GetProfileDataAsync(ProfileDataRequestContext上下文)
{
列表声明=新列表();
foreach(上下文中的IdentityResource IdentityResource.RequestedResources.IdentityResources)
{
foreach(identityResource.UserClaims中的字符串userClaim)
{
var-claim=context.Subject.Claims.FirstOrDefault(c=>c.Type==userClaim);
如果(索赔!=null)
{
索赔。添加(索赔);
}
}
}
if(claims.Any())
{
context.IssuedClaims.AddRange(索赔);
}
返回Task.CompletedTask;
}
}
现在,当我调用
userinfo
端点时,我的自定义声明是可见的

但是在检查访问令牌之后,我可以看到我的自定义声明也在那里可见。我觉得这有点多余,因为您(在本例中)实际上不必调用
userinfo

如果没有自定义的
IProfileService
实现(类仍然存在,但只有一个空方法),我会进行以下观察:

  • context.Subject.Claims
    在调用
    token
    端点时包含自定义声明,但在从
    userinfo
    调用时不包含自定义声明
  • 数据库中的
    PersistedGrants
    表有一个
    Data
    列,该列还包含自定义标记

所以问题仍然是:如何防止自定义声明出现在访问令牌中,并且仅在调用
userinfo
端点时返回?

我认为这可能是一个配置问题

必须使用2个允许的作用域定义客户端:

  • IdentityServerConstants.StandardScopes.OpenId
  • “定制”
新客户端
{
AllowedScopes=新列表
{
IdentityServerConstants.StandardScopes.OpenId,
“定制”
},
//等等。。。
然后在客户端上配置
ResponseType=OpenIdConnectResponseType.IdTokenToken;

.AddOpenIdConnect(o=>
{
o、 Scope.Clear();
o、 范围。添加(“openid”);
o、 范围。添加(“自定义”);
o、 ResponseType=OpenIdConnectResponseType.IdTokenToken;
//等等。。。

我认为这可能是一个配置问题

必须使用2个允许的作用域定义客户端:

  • IdentityServerConstants.StandardScopes.OpenId
  • “定制”
新客户端
{
AllowedScopes=新列表
{
IdentityServerConstants.StandardScopes.OpenId,
“定制”
},
//等等。。。
然后在客户端上配置
ResponseType=OpenIdConnectResponseType.IdTokenToken;

.AddOpenIdConnect(o=>
{
o、 Scope.Clear();
o、 范围。添加(“openid”);
o、 范围。添加(“自定义”);
o、 ResponseType=OpenIdConnectResponseType.IdTokenToken;
//等等。。。

您可以检查调用方是否为
/userinfo
(我假设这就是包含该属性的初衷):


您可以检查调用方是否为
/userinfo
(我假设这就是包含该属性的最初意图):


我认为您应该检查ApiResource配置。无论您在ApiResource配置的UserClaims属性中添加了什么声明,这些声明都将出现在访问令牌中

 public IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("api1")
                {
                    UserClaims = new[] { "CustomClaim1", "CustomClaim2"},
                }, 
             }
        }
public IEnumerable GetApiResources()
{
返回新列表
{
新ApiResource(“api1”)
{
UserClaims=new[]{“CustomClaim1”、“CustomClaim2”},
}, 
}
}
在上面的代码中,访问代码将包含CustomClaim1和CustomClaim2。
因此,如果您不提及它们,它们将不会出现在访问令牌中。

我认为您应该检查ApiResource配置。无论您在ApiResource配置的UserClaims属性中添加了什么声明,这些声明都将出现在访问令牌中

 public IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("api1")
                {
                    UserClaims = new[] { "CustomClaim1", "CustomClaim2"},
                }, 
             }
        }
public IEnumerable GetApiResources()
{
返回新列表
{
新ApiResource(“api1”)
{
UserClaims=new[]{“CustomClaim1”、“CustomClaim2”},
}, 
}
}
在上面的代码中,访问代码将包含CustomClaim1和CustomClaim2。
因此,如果您不提及它们,它们将不会出现在访问令牌中。

我的客户机已经将
自定义
添加到允许的作用域中,并且我正在使用
授权\u code
授权类型,因此我只能使用“code”作为响应类型。我的客户机已将
自定义
添加到允许的作用域中,并且我正在使用
授权_code
授予类型,因此我只能使用“code”作为响应类型。如果我没有执行
GetProfileDataAsync
,则
 public IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("api1")
                {
                    UserClaims = new[] { "CustomClaim1", "CustomClaim2"},
                }, 
             }
        }