如何将列表<Claim>转换为字典<string,object>?

问题描述 投票:0回答:2

我收到了要添加 jwt 令牌的声明

获取有效声明并生成 Jwt 令牌

var claims = await GetValidClaims(users);
Token = GenerateJwtToken(users, claims);

生成JwtToken方法

private string GenerateJwtToken(ApplicationUser user, List<Claim> claims)
{
    var dicClaim = new Dictionary<string,object>();
    ...
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Claims = dicClaim,   // <<<<<<<<<< this Claims is Dictionary<string,object>
        ...
    }
}

GetValidClaims 方法

private async Task<List<Claim>> GetValidClaims(ApplicationUser user)
{
    IdentityOptions _options = new IdentityOptions();
    var claims = new List<Claim>
    {
        new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
        new Claim(_options.ClaimsIdentity.UserIdClaimType, user.Id.ToString()),
        new Claim(_options.ClaimsIdentity.UserNameClaimType, user.UserName)
    };
    var userClaims = await _userManager.GetClaimsAsync(user);
    var userRoles = await _userManager.GetRolesAsync(user);
    claims.AddRange(userClaims);
    foreach (var userRole in userRoles)
    {
        claims.Add(new Claim(ClaimTypes.Role, userRole));
        var role = await _roleManager.FindByNameAsync(userRole);
        if (role != null)
        {
            var roleClaims = await _roleManager.GetClaimsAsync(role);
            foreach (Claim roleClaim in roleClaims)
            {
                claims.Add(roleClaim);
            }
        }
    }
    return claims;
}

在这一行:

Claims = dicClaim,   // <<<<<<<<<< this Claims is Dictionary<string,object>

但是我不知道如何将List转换为Dictionary

我已经尝试过这样的事情:

claims.ToDictionary(x=>x,x=>x.Value)

claims.ToDictionary(x=>x.Value,x=>x)

图书馆

SecurityTokenDescriptor

c# list dictionary
2个回答
6
投票

为了创建一个字典,我们必须为其定义一个unique

Key
。假设

  1. 我们希望我们的密钥be说,
    Type
    或至少从Type
    开始
  2. 索赔可以
  3. 重复
我们可以这样解决:

  1. Group
     
    Type
    (所需密钥)
    的所有索赔
  2. 如果组中只有
  3. 1
     声明,请使用 
    Value
     作为 
    Key
    
    
  4. 如果没有,让我们生成
  5. Type_1
    , 
    Type_2
    , ..., 
    Type_N
     
    Key
    s
代码

var dicClaim = claims .GroupBy(claim => claim.Type) // Desired Key .SelectMany(group => group .Select((item, index) => group.Count() <= 1 ? Tuple.Create(group.Key, item) // One claim in group : Tuple.Create($"{group.Key}_{index + 1}", item) // Many claims )) .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2);

如果遇到

repeated 声明,您只想获得 Last

 一个,您可以使用以下代码来实现:

var dicClaim = claims .GroupBy(claim => claim.Type) // Desired Key .ToDictionary(group => group.Key, group => group.Last());
    

0
投票
我来到这里是因为我在构建 JSON Web Tokens (JWT) 时从使用

System.IdentityModel.Tokens.Jwt

IList<Claims>
 升级到使用 
Microsoft.IdentityModel.JsonWebTokens
Dictionary<string,object>
。 Dmitry 在 2019 年提供的答案正如他所描述的那样,但我认为这不是 JWT 的正确方法。例如,如果您有两个角色声明,使用 Dmitry 的方法将生成如下声明:

{ "role_1": "User", "role_2": "Manager" }
不幸的是,你在 JWT 中真正想要的是:

{ "role": [ "User", "Manager" ] }
更令人困惑的是,如果用户只有一个角色,JWT 不使用 JSON 数组:

{ "role": "Manager" }
因此,考虑到这些要求,这里有一个处理这两种情况的简单扩展方法:

public static Dictionary<string, object> ToClaimsDictionary( this IEnumerable<Claim> claims) => claims .GroupBy(i => i.Type) .ToDictionary( i => i.Key, i => (object)(i.Count() == 1 ? i.First().Value : i.Select(i => i.Value).ToArray()));
    
© www.soinside.com 2019 - 2024. All rights reserved.