delphi TIdDecoderMIME.DecodeString丢失最后一个解码字符

xhv8bpkk  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(226)

我想在 Delphi XE 5中解码一个简单的JWT Token,但是当我按如下所示执行时,decodedPayload缺少JSON对象的最后一个}
我做错了什么?

function getIssuerFromToken(token: string): string;
var
  tokenPayload, decodedTokenPayload, issuer: string;
  tokenJSONValue: TJSONValue;
  tokenJSONWrapper: TKJSONWrapper;
  tokenPayloadStartIndex, tokenPayloadEndIndex, tokenPayLoadLength: integer;
begin
  tokenPayloadStartIndex := Pos('.', token) + 1;
  tokenPayloadEndIndex := Pos('.', token, tokenPayloadStartIndex);
  tokenPayLoadLength := tokenPayloadEndIndex - tokenPayloadStartIndex;

  tokenPayload := Copy(token, tokenPayloadStartIndex, tokenPayLoadLength);
  decodedTokenPayload := TIdDecoderMIME.DecodeString(tokenPayload);
...
whitzsjs

whitzsjs1#

根据JSON Web Token规范的RFC 7519,JWT令牌由以句点分隔的base64 url编码部分组成。base64 url编码在RFC 7515中针对JSON Web签名规范进行了描述。根据该规范,base64没有填充:
Base64 url编码
使用RFC 4648 [RFC 4648]第5节中定义的URL和文件名安全字符集的Base64编码,省略所有尾随的'='字符(如第3.2节所允许的),并且不包含任何换行符,空格或其他附加字符。注意,空八位字节序列的base64 url编码是空字符串。(参见附录C,了解关于实现base64 url编码而不使用填充的说明。
由于base64要求输入是4个字符的偶数倍,因此在解码之前需要向base64数据添加填充。你也需要在解码之前对base64进行url解码。RFC 7515甚至在附录C中提供了一个示例实现:

static byte [] base64urldecode(string arg)
{
  string s = arg;
  s = s.Replace('-', '+'); // 62nd char of encoding
  s = s.Replace('_', '/'); // 63rd char of encoding
  switch (s.Length % 4) // Pad with trailing '='s
  {
    case 0: break; // No pad chars in this case
    case 2: s += "=="; break; // Two pad chars
    case 3: s += "="; break; // One pad char
    default: throw new System.Exception(
      "Illegal base64url string!");
  }
  return Convert.FromBase64String(s); // Standard base64 decoder
}

此外,base64中的JSON必须是UTF-8编码的,因此在解码base64时也必须考虑到这一点。TIdDecoderMIME使用的默认字节编码是8位而不是UTF-8,但它的DecodeString()方法确实有一个可选的AByteEncoding参数,因此您可以指定UTF-8。
所以,在你的代码中尝试类似下面的东西:

function decodeJWTpart(const base64: string): string;
var
  s: string;
begin
  s := base64;
  s := StringReplace(s, '-', '+', [rfReplaceAll]);
  s := StringReplace(s, '_', '/', [rfReplaceAll]);
  case Length(s) mod 4 of
    0: ;
    2: s := s + '==';
    3: s := '=';
  else
    raise Exception.Create('Illegal base64url string!');
  end;
  Result := TIdDecoder.DecodeString(s, IndyTextEncoding_UTF8);
end;

function getIssuerFromToken(const token: string): string;
var
  tokenPayload, ...: string;
  ...
begin
  ...
  decodedTokenPayload := decodeJWTpart(tokenPayload);
  ...
end;

相关问题