TextEncodings.Base64Url.Decode 与 Convert.FromBase64String

TextEncodings.Base64Url.Decode vs Convert.FromBase64String

我正在努力创建一种可以生成 JWT 令牌的方法。该方法的一部分从我的 web.config 中读取一个值,该值作为 "secret" 用于生成用于为 JWT 令牌创建签名的散列。

<add key="MySecret" value="j39djak49H893hsk297353jG73gs72HJ3tdM37Vk397" />

最初我尝试使用以下方法将 "secret" 值转换为字节数组。

byte[] key = Convert.FromBase64String(ConfigurationManager.AppSettings["MySecret"]);

然而,当到达这一行时抛出异常...

输入的 Base-64 字符串无效,因为它包含非 64 位字符、两个以上的填充字符或填充字符中的非法字符。

所以我查看了 OAuth 代码以及另一种用于将 base64 字符串更改为字节数组的方法

byte[] key = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["MySecret"]);

这个方法没有问题。在我看来,他们似乎在做同样的事情。将 Base64 文本值更改为字节数组。但是,我必须遗漏一些东西。为什么 Convert.FromBase64String 失败而 TextEncodings.Base64Url.Decode 有效?

我在将身份验证服务迁移到 .NET Core 时遇到了同样的事情。我查看了我们在之前的实现中使用的库的源代码,区别实际上在于名称本身。

TextEncodings class 有两种类型的文本编码器,Base64TextEncoder 和 Base64UrlEncoder。后者稍微修改了字符串,因此可以在 url.

中使用 base64 字符串

我的理解是quite common to replace + and / with - and _. As a matter of fact we have been doing the same with our handshake tokens. Additionally the padding character(s) at the end can also be removed. This leaves us with the following implementation (this is from the source code):

public class Base64UrlTextEncoder : ITextEncoder
{
    public string Encode(byte[] data)
    {
        if (data == null)
        {
            throw new ArgumentNullException("data");
        }

        return Convert.ToBase64String(data).TrimEnd('=').Replace('+', '-').Replace('/', '_');
    }

    public byte[] Decode(string text)
    {
        if (text == null)
        {
            throw new ArgumentNullException("text");
        }

        return Convert.FromBase64String(Pad(text.Replace('-', '+').Replace('_', '/')));
    }

    private static string Pad(string text)
    {
        var padding = 3 - ((text.Length + 3) % 4);
        if (padding == 0)
        {
            return text;
        }
        return text + new string('=', padding);
    }
}