验证JWT签名时读取JWK文件n/e字段遇System.FormatException
问题分析与解决
问题背景
尝试通过服务器托管的JWK文件验证JWT签名,定义了Jwk模型并实现了验证逻辑,但在转换JWK的n和e字段时抛出System.FormatException,提示输入不是有效的Base64字符串。
代码与错误信息
Jwk模型
public class Jwk{ [JsonProperty("alg")] public string Alg { get; set; } [JsonProperty("e")] public string E { get; set; } [JsonProperty("kty")] public string Kty { get; set; } [JsonProperty("n")] public string N { get; set; } [JsonProperty("use")] public string Use { get; set; } }
验证方法
public TokenValidationParameters VerifyToken(Jwk jwk) { // 此处抛出异常 RSAParameters rsaParams = new RSAParameters { Modulus = Convert.FromBase64String(jwk.N), Exponent = Convert.FromBase64String(jwk.E), }; using RSA rsa = RSA.Create(); rsa.ImportParameters(rsaParams); var validationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, IssuerSigningKey = new RsaSecurityKey(rsa) }; return validationParameters; }
错误信息
System.FormatException: 'The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.'
所用JWK数据
{ "kty": "RSA", "n": "qum6HexDv55WPr9iqoO-yOoqGRiFaF0Vx7YAigPYsLdyAgnmQRKxI81_XgJfH_f18mNO_j4GCVLIzvQYZGFw9cIs3b3kt9frxNssc24_Uh6zccvE2XWn9yr81OYu85OfL4mgA1WQPm-ZKIzvPq77ISY51PBSpK6FQkwuc9OhWDk", "e": "AQAB", "alg": "RS256", "use": "sig" }
解决方法
问题核心是JWK中的n和e采用的是Base64URL编码,而非标准Base64编码,两者的差异如下:
- Base64URL用
-替代标准Base64的+ - 用
_替代/ - 省略末尾的填充符
=
需要先将Base64URL转换为标准Base64,再进行解析。实现转换方法:
private static byte[] Base64UrlDecode(string base64Url) { // 替换特殊字符为标准Base64格式 string base64 = base64Url.Replace('-', '+').Replace('_', '/'); // 补充缺失的填充字符 switch (base64.Length % 4) { case 2: base64 += "=="; break; case 3: base64 += "="; break; } return Convert.FromBase64String(base64); }
修改验证方法,使用上述转换方法替代原有的Convert.FromBase64String,同时清理可能存在的换行符:
public TokenValidationParameters VerifyToken(Jwk jwk) { // 清理反序列化时可能保留的换行符 string cleanN = jwk.N.Replace("\n", "").Replace("\r", ""); string cleanE = jwk.E.Replace("\n", "").Replace("\r", ""); RSAParameters rsaParams = new RSAParameters { Modulus = Base64UrlDecode(cleanN), Exponent = Base64UrlDecode(cleanE), }; using RSA rsa = RSA.Create(); rsa.ImportParameters(rsaParams); var validationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, IssuerSigningKey = new RsaSecurityKey(rsa) }; return validationParameters; }
内容的提问来源于stack exchange,提问作者rabner casandra
相关产品推荐
相关产品推荐

