C#手动生成JWT签名无效问题排查求助
手动实现C# JWT签名访问Google Calendar的签名问题解决办法
问题核心
手动实现JWT用于Google Calendar接口调用时,签名在验证工具中始终显示无效,最终确认问题根源是未使用gcloud shell获取的正确Google Cloud公钥。
核心实现代码
以下是提取出的JWT生成与签名核心函数:
// 生成JWT主函数 private static string GenerateJwt(string clientEmail, string privateKey, string scope, string audience) { // 构建JWT Header var header = new { alg = "RS256", typ = "JWT" }; var headerJson = JsonSerializer.Serialize(header); var headerBase64 = Base64UrlEncode(headerJson); // 构建JWT Payload(符合Google OAuth2要求) var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); var payload = new { iss = clientEmail, scope = scope, aud = audience, exp = now + 3600, // 有效期1小时,不超过Google限制 iat = now }; var payloadJson = JsonSerializer.Serialize(payload); var payloadBase64 = Base64UrlEncode(payloadJson); // 拼接待签名的原始内容 var unsignedJwt = $"{headerBase64}.{payloadBase64}"; // 使用RSA私钥签名 var signatureBytes = SignWithRsaPrivateKey(unsignedJwt, privateKey); var signatureBase64 = Base64UrlEncode(signatureBytes); return $"{unsignedJwt}.{signatureBase64}"; } // JWT专用Base64URL编码(处理字符串) private static string Base64UrlEncode(string input) { var bytes = Encoding.UTF8.GetBytes(input); return Convert.ToBase64String(bytes) .Replace('+', '-') .Replace('/', '_') .TrimEnd('='); } // JWT专用Base64URL编码(处理字节数组) private static string Base64UrlEncode(byte[] input) { return Convert.ToBase64String(input) .Replace('+', '-') .Replace('/', '_') .TrimEnd('='); } // RSA私钥签名核心逻辑(适配Google要求的RS256算法) private static byte[] SignWithRsaPrivateKey(string data, string privateKey) { // 清理PEM格式私钥的头部、尾部和换行符 var cleanedPrivateKey = privateKey .Replace("-----BEGIN PRIVATE KEY-----", "") .Replace("-----END PRIVATE KEY-----", "") .Replace("\n", "") .Replace("\r", ""); var privateKeyBytes = Convert.FromBase64String(cleanedPrivateKey); using var rsa = RSA.Create(); rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _); // Google要求使用SHA256哈希+PSS填充方式 return rsa.SignData(Encoding.UTF8.GetBytes(data), HashAlgorithmName.SHA256, RSASignaturePadding.Pss); }
问题排查与解决要点
签名无效的常见诱因:
- 私钥格式错误:未正确移除PEM格式的头部/尾部标记、换行符,导致无法正常导入RSA对象
- 签名算法不匹配:Google OAuth2要求使用RS256(SHA256+RSA-PSS),需确保签名时使用对应参数
- 验证用公钥错误:之前使用的公钥与服务账号不匹配,必须通过官方渠道获取有效公钥
获取正确Google Cloud公钥的方式:
通过gcloud命令行工具执行以下命令(替换为你的服务账号邮箱):gcloud iam service-accounts keys list --iam-account=your-service-account@your-project-id.iam.gserviceaccount.com从输出中获取对应密钥的公钥信息,或导出密钥文件后提取公钥部分,用于JWT签名验证。
内容的提问来源于stack exchange,提问作者Paolo Concari
相关产品推荐
相关产品推荐

