我通常尝试做的是验证从OpenID Connect提供商(例如Google)获得的 id_token 值。令牌使用RSA算法进行签名,并从Discovery文档( jwks_uri 参数)中读取公钥。例如,Google密钥以JWK格式提供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 。根据{{3}},这些值是Base64urlUInt编码的值:
表示正整数或零整数值 base64url编码值的无符号大端表示 作为八位字节序列。八位位组序列必须使用最小值 表示该值所需的八位字节数。代表零 as BASE64URL(单个零值八位字节),即" AA"。
所以,我的问题是如何解码这些值以将它们放到RSAParameters中?我尝试将它们解码为常见的Base64url字符串(Convert.FromBase64String(modulusRaw)
),但这显然不起作用并生成此错误:
输入不是有效的Base-64字符串,因为它包含非基数64 字符,两个以上的填充字符或非法字符 在填充字符中。
答案 0 :(得分:4)
RFC 7515定义了base64url编码,如下所示:
使用URL和文件名安全字符集的Base64编码 在RFC 4648的第5节中定义,所有尾随' =' 省略字符(如第3.2节所允许)并且没有 包含任何换行符,空格或其他附加内容 字符。注意空八位字节的base64url编码 sequence是空字符串。 (有关说明,请参阅附录C. 在没有填充的情况下实现base64url编码。)
RFC 4648定义" Base 64编码,带有URL和文件名安全字母"作为常规base64,但是:
-
代替+
和_
代替/
因此,要使用常规Convert.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);
}
这个代码可能已经存在于框架中的某个地方,但我并不知道它。
答案 1 :(得分:0)
谁从Java来的:java.util.Base64
中有两种方法:
getDecoder()
getUrlDecoder()
您可能已经猜到了:第二个已经为您完成了所有字符替换。