解码jwt错误:无法将有效负载解码为Base64Url编码的字符串

时间:2017-03-28 16:23:15

标签: c# node.js base64 jwt

我有一个jwt令牌' eyJhbGciOiJIUzI1NiJ9.YUExIQ.srnc87a8Se8arhCopLBpgxEvILA2AZxOB8BIrFDHKL4 ' 这是在节点中编码而我试图在c#中对其进行解码,但是我发现了一个错误,它对有效载荷感到不满。

    public void Consume(BasicDeliverEventArgs msg)
    {
        var message = Encoding.UTF8.GetString(msg.Body);
        var user = JsonConvert.DeserializeObject<User>(message);

        var handler = new JwtSecurityTokenHandler();

        try
        {    
            var x = handler.ReadToken(user.Password) as JwtSecurityToken;
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }



        _repo.UpdateUser(user);
    }

返回错误:无法解码有效负载&#39; YUExIQ&#39;作为Base64Url编码的字符串

我不知道是否在某个地方我可以将用于编码的秘密放在某处的解码中,或者我是否需要将有效负载转换为base64,或者我是否只是在某处丢失某些步骤。提前致谢。

3 个答案:

答案 0 :(得分:0)

使用JWT,省略填充字节。 .NET要求在末尾填充=个字符,以使字符数为4的倍数。YUExIQ==应该是可解码的。

答案 1 :(得分:0)

由于您询问了使用Base64解码,我将专注于该问题,而不是.NET中JWT的语义。这应该揭开JWT代币的神秘面纱。

请注意,只有上面JWT字符串的第一段有效 - 它转换为{"alg":"HS256"},而第二段转换为aA1! - 所以例如,我将使用来自的默认样本值http://jwt.io

var jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";

因此,根据JWT.io's introduction,您在JWT令牌中只有三个段:

  • 标题
  • 有效载荷
  • 签名

假设令牌未加密,可以使用普通Base64对前两个段进行解码(一旦将长度填充为四的倍数,如上面提到的@Jacob)。最后一段只是一个加密签名;它不包含任何有意义的编码信息进行解码。

因此,显示解码的JWT内容的简单代码片段如下所示:

var decoded = jwt.Split('.')
  .Take(2)
  .Select(x => 
    Encoding.UTF8.GetString(
      Convert.FromBase64String(
        x.PadRight(x.Length + (x.Length % 4), '='))))
.Aggregate((s1, s2) => s1 + Environment.NewLine + s2);

Console.WriteLine(decoded);

/* Prints:
   {
     "alg": "HS256",
     "typ": "JWT"
   }
   {
     "sub": "1234567890",
     "name": "John Doe",
     "admin": true
   }
*/

分隔所有lambdas的简单示例可能如下所示:

/// <summary>
/// A function to make the Base64 decoding a little less
/// verbose below:
/// </summary>
string Base64Decode(string value)
{
    return Encoding.Default.GetString(Convert.FromBase64String(value)); 
}

// Get the first two segments into an enumerable:
var pieces = jwt.Split('.').Take(2);
// Pad them with equals signs to a length that is a multiple of four:
var paddedPieces = pieces.Select(x => x.PadRight(x.Length + (x.Length % 4), '='));
// Base64 decode the pieces:
var decodedPieces = paddedPieces.Select(x => Base64Decode(x));
// Join it all back into one string with .Aggregate:
Console.WriteLine(decodedPieces.Aggregate((s1, s2) => s1 + Environment.NewLine + s2));

此处的结果与上面的结果相同。

当然,如果您打算执行有意义的JWT操作(如签名和验证),则应使用System.IdentityModel.Tokens.Jwt中的JwtSecurityToken类。但是,如果您只需要找出非加密令牌包含的信息,就会像上面那样简单。

答案 2 :(得分:0)

我无法添加评论,仅想添加到@ paul-smith答案。

他的答案有效,但是在逻辑上有一个小错误,可将字符串填充为4的倍数。

而不是

var paddedPieces = pieces.Select(x => x.PadRight(x.Length + (x.Length % 4), '='));

应该是...

var paddedPieces = pieces.Select(x => x.PadRight(x.Length + ((x.Length % 4 != 0) ? (4 - x.Length % 4) : 0), '='));

您需要检查“ x.Length%4!= 0”,否则在字符串已经是4的倍数而使Base64解码中断的情况下,可能会在末尾添加“ ====”。但是真正的问题是应该是(4-x.Length%4),而不是(x.Length%4)

例如

如果字符串长度为7个字符...

7 +(7%4)= 10
7 +(4-(7%4)= 8