所以我想在 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);
...
根据 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;