JWT解码时字符串声明类型错误?

Posted

技术标签:

【中文标题】JWT解码时字符串声明类型错误?【英文标题】:String Claim Types Error when JWT Decoding? 【发布时间】:2022-01-15 17:00:07 【问题描述】:

当我进行登录操作时,JWT 令牌作为响应返回。但是,当我用 JS 解码时,我得到了这个:

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: '1', http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: 'RESMAK ', http://schemas.microsoft.com/ws/2008/06/identity/claims/role: 'Administrator', FirmNumber: '1', PeriodNumber: '1', …
FirmNumber: "1"
PeriodNumber: "1"
aud: "Audience"
exp: 1639301639
http://schemas.microsoft.com/ws/2008/06/identity/claims/role: "Administrator"
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: "RESMAK "
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: "1"
iss: "Issuer"
nbf: 1639215239
[[Prototype]]: Object

我想成为这样的人

FirmNumber: "1"
PeriodNumber: "1"
aud: "Audience"
exp: 1639301639
role: "Administrator"
name: "RESMAK "
nameidentifier: "1"
iss: "Issuer"

可能是什么原因? .Net Core 3.1 与 TypeScript 反应

我通过 JwtHelper 类创建令牌


public class JwtHelper
 
     public IConfiguration Configuration  get; 
     private TokenOptions _tokenOptions;
     private DateTime _accessTokenExpiration;

     public JwtHelper(IConfiguration configuration)
     
         Configuration = configuration;
         _tokenOptions = Configuration.GetSection("TokenOptions").Get<TokenOptions>();
     
     public AccessToken CreateToken(User user, List<OperationClaim> operationClaims, UserForLoginDto userForLoginDto)
     
         _accessTokenExpiration = DateTime.Now.AddMinutes(_tokenOptions.AccessTokenExpiration);
         var securityKey = SecurityKeyHelper.CreateSecurityKey(_tokenOptions.SecurityKey);
         var signingCredentials = SigningCredentialsHelper.CreateSigningCredentials(securityKey);
         var jwt = CreateJwtSecurityToken(_tokenOptions, user, operationClaims, userForLoginDto, signingCredentials);
         var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
         var token = jwtSecurityTokenHandler.WriteToken(jwt);

         return new AccessToken
         
             Token = token,
             Expration = _accessTokenExpiration
         ;
     

     //securityKey ,signingCredentials ve diger token optionsdan gelen bilgileri toplayarak bir JwtToken Üretiyoruz.
     public JwtSecurityToken CreateJwtSecurityToken(TokenOptions tokenOptions, User user, List<OperationClaim> operationClaims, UserForLoginDto userForLoginDto, SigningCredentials signingCredentials)
     
         var jwt = new JwtSecurityToken
         (
            issuer: tokenOptions.Issuer,
            audience: tokenOptions.Audience,
            expires: _accessTokenExpiration,
            notBefore: DateTime.Now,
            claims: SetClaims(user, operationClaims, userForLoginDto),
            signingCredentials: signingCredentials
         );
         return jwt;
     

     private IEnumerable<Claim> SetClaims(User user, List<OperationClaim> operationClaims, UserForLoginDto userForLoginDto)
     
         var claims = new List<Claim>();
         claims.AddNameIdentifier(user.Id.ToString());
         claims.AddName($"user.FirstName user.LastName");
         claims.AddRoles(operationClaims.Select(x => x.Name).ToArray());
         claims.AddFirmNumber(userForLoginDto.FirmNumber.ToString());
         claims.AddPeriodNumber(userForLoginDto.PeriodNumber.ToString());
         return claims;
     
 


public static class ClaimExtensions
 

     public const string ClaimTypeFirmNumber = "FirmNumber";
     public const string ClaimTypePeriodNumber = "PeriodNumber";


     public static void AddName(this ICollection<Claim> claims, string name)
     
         claims.Add(new Claim(ClaimTypes.Name, name));
     
     public static void AddNameIdentifier(this ICollection<Claim> claims, string nameIdentifier)
     
         claims.Add(new Claim(ClaimTypes.NameIdentifier, nameIdentifier));
     
     public static void AddRoles(this ICollection<Claim> claims, string[] roles)
     
         foreach (var role in roles)
         
             claims.Add(new Claim(ClaimTypes.Role, role));
         

     
     public static void AddPeriodNumber(this ICollection<Claim> claims, string periodNumber)
     
         claims.Add(new Claim(ClaimTypePeriodNumber, periodNumber));
     
     public static void AddFirmNumber(this ICollection<Claim> claims, string firmNumber)
     
         claims.Add(new Claim(ClaimTypeFirmNumber, firmNumber));
     

 

我使用 SigningCredentials 作为 SecurityAlgorithms.HmacSha256Signature

  public class SigningCredentialsHelper
    
        public static SigningCredentials CreateSigningCredentials(SecurityKey securityKey)
        
            return new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);//GEnellikle bu şifreleme algoritması kullanılır
        
    

最后我用 JwtDecode 库解码了令牌 const decodedToken = jwtDecode(response.data.token)

【问题讨论】:

嗯,这些声明类型名称是默认值。您究竟是如何生成 JWT 的? edit你的问题向我们展示 @CamiloTerevinto 我编辑了 【参考方案1】:

问题在于 OpenIDConnect/OAuth 和 Microsoft 对声明名称应该是什么有不同的看法,默认情况下 .NET 会在幕后重命名一些声明。

要阻止这种情况,您需要使用以下方式关闭声明映射:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();

然后您需要通过设置来告诉 .NET 名称/角色声明的名称应该是什么:

opt.TokenValidationParameters.RoleClaimType = "roles";
opt.TokenValidationParameters.NameClaimType = "name";

有关索赔映射的更多详细信息,请访问:

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/claims?view=aspnetcore-6.0

【讨论】:

以上是关于JWT解码时字符串声明类型错误?的主要内容,如果未能解决你的问题,请参考以下文章

在 Clojure/Java 中解码 JWT

JWT 如何添加自定义声明和解码声明

尝试解码 Jwt 令牌时出现“尝试解码 Jwt 时发生错误:无法检索远程 JWK 集:”错误

解码 jwt 时,AuthenticationEvent 未发布错误

从 Google 解码 JWT 字符串失败 [php]

@auth0/angular-jwt : 从解码的令牌中获取声明