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

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

我想在 Delphi XE5 中解码一个简单的 JWT 令牌,但是当我如下所示执行时,

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);
...
delphi indy delphi-xe5 indy10
1个回答
0
投票

根据 JSON Web 令牌规范的 RFC 7519,JWT 令牌由以句点分隔的 base64url 编码部分组成。 JSON Web 签名规范的 RFC 7515 中描述了 base64url 编码。根据该规范,所使用的 base64 未填充。

在解码之前,您需要向 Base64 添加填充。您还需要在解码之前对其进行 url 解码。 RFC 甚至在附录 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 编码的,因此您也必须考虑到这一点。

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;
© www.soinside.com 2019 - 2024. All rights reserved.