我通常要做的是验证从openid connect提供商(如google)获得的id_令牌值。令牌是用rsa算法签名的,公钥是从Discovery文档(jwks-uri参数)中读取的。例如,可以使用jwk格式的google键here

{
  kty: "RSA",
  alg: "RS256",
  use: "sig",
  kid: "38d516cbe31d4345819b786d4d227e3075df02fc",
  n: "4fQxF6dFabDqsz9a9-XgVhDaadTBO4yBZkpUyUKrS98ZtpKIQRMLoph3bK9Cua828wwDZ9HHhUxOcbcUiNDUbubtsDz1AirWpCVRRauxRdRInejbGSqHMbg1bxWYfquKKQwF7WnrrSbgdInUZPv5xcHEjQ6q_Kbcsts1Nnc__8YRdmIGrtdTAcm1Ga8LfwroeyiF-2xn0mtWDnU7rblQI4qaXCwM8Zm-lUrpSUkO6E1RTJ1L0vRx8ieyLLOBzJNwxpIBNFolMK8-DYXDSX0SdR7gslInKCn8Ihd9mpI2QBuT-KFUi88t8TW4LsoWHAwlgXCRGP5cYB4r30NQ1wMiuQ",
  e: "AQAB"
}

我将使用RSACryptoServiceProvider类来解码签名。要初始化它,我必须提供RSAParameters的模和指数值。这些值从上述JWK中相应地读取为n和e。根据specification,这些值是base64urluint编码的值:
正整数值或零整数值表示为
值的无符号大端表示的base64url编码
作为八进制序列。八进制序列必须使用
表示该值所需的八位字节数。表示零
作为base64url(单零值八位字节),即“aa”。
所以,我的问题是如何解码这些值,将它们放入rsaparameters?我尝试将它们解码为公共base64url字符串(Convert.FromBase64String(modulusRaw)),但这显然不起作用,并生成以下错误:
输入不是有效的base-64字符串,因为它包含非base 64
字符、两个以上的填充字符或非法字符
在填充字符之间。

最佳答案

RFC 7515定义base64url编码如下:
使用URL和文件名安全字符集的Base64编码
RFC 4648的第5节中定义,所有尾随“=”
省略的字符(如第3.2节所允许)和没有
包含任何换行符、空白或其他附加的
角色。注意,空八位字节的base64url编码
序列是空字符串。(有关
实现不带填充的base64url编码。)
RFC 4648将“使用URL和文件名安全字母表的base64编码”定义为常规base64,但是:
填充可以省略(因为它在这里)
-代替+_代替/
因此,要使用regularConvert.FromBase64String,您只需反转该过程:

static byte[] FromBase64Url(string base64Url)
{
    string padded = base64Url.Length % 4 == 0
        ? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
    string base64 = padded.Replace("_", "/")
                          .Replace("-", "+");
    return Convert.FromBase64String(base64);
}

这个代码可能已经存在于框架中的某个地方,但我不知道。

07-24 18:30