You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}

问题排查与解决要点

  1. 签名无效的常见诱因:

    • 私钥格式错误:未正确移除PEM格式的头部/尾部标记、换行符,导致无法正常导入RSA对象
    • 签名算法不匹配:Google OAuth2要求使用RS256(SHA256+RSA-PSS),需确保签名时使用对应参数
    • 验证用公钥错误:之前使用的公钥与服务账号不匹配,必须通过官方渠道获取有效公钥
  2. 获取正确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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 11:47:12