生成的 JSON Web Token 不被 Google API Service 接受



我已经创建了一个服务帐户,并在 Google Cloud Platform 上下载了我的 JSON 凭据。我需要在.NET中对DialogFlow Service API进行REST POST调用。目前,我只能使用PowerShell中生成的令牌来执行此操作。由于我需要从脚本完成所有操作,因此我需要生成一个 JWT 以在我的 REST 调用中作为我的持有者传递。我的问题是生成的 JWT 不被谷歌接受。

我根据此文档页面在 PowerShell 中得到响应,并从此文档页面复制示例代码以创建我的 JWT。

public static string GetSignedJwt(string emailClient, string 
dialogueFlowServiceApi, string privateKeyId, string privateKey, string 
jsonPath)
{
    // to get unix time in seconds
    var unixTimeSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
    // start time of Unix system
    var origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
    // adding milliseconds to reach the current time, it will be used for issueAt time
    var nowDataTime = origin.AddSeconds(unixTimeSeconds);
    // one hour after the current time, it will be used for expiration time
    var oneHourFromNow = nowDataTime.AddSeconds(3600);
    // holder of signed json web token that we will return at the end
    var signedJwt = "";
    try
    {
        // create our payload for Jwt
        var payload = new Dictionary<string, object>
        {
            {"iss", emailClient},
            {"sub", emailClient},
            {"aud", dialogueFlowServiceApi},
            {"iat", nowDataTime},
            {"exp", oneHourFromNow}
        };
        // create our additional headers
        var extraHeaders = new Dictionary<string, object>
        {
            {"kid", privateKeyId}
        };
        IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
        IJsonSerializer serializer = new JsonNetSerializer();
        IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
        IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
        signedJwt = encoder.Encode(extraHeaders, payload, privateKey);
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        // return null if there has been any error
        return null;
    }
    finally
    {
        Console.WriteLine(signedJwt);
    }
    return signedJwt; 
}

请注意,需要通过传递公钥和私钥在 RSA256 中进行签名,就像 Google 在 Java 示例片段中所做的那样,但是,当我使用该算法时,我在 .Net 中的等效项只给了我Object reference not set to an instance of an object

var key = RSA.Create(privateKey);
IJwtAlgorithm algorithm = new RS256Algorithm(null, key);
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
signedJwt = encoder.Encode(extraHeaders, payload, privateKey);

除了正确的键外,我还使用https://dialogflow.googleapis.com/google.cloud.dialogflow.v2beta1.Intents作为dialogFlow服务API键。

我希望我生成的 JWT 被接受,但它被谷歌拒绝了。

1(您使用了错误的算法

更改此行代码:

IJwtAlgorithm algorithm = new RS256Algorithm(null, key);

对此:

IJwtAlgorithm algorithm = new HMACSHA256Algorithm();

2( 对于 JWT 标头:

var additional_headers = new Dictionary<string, object>
{
    { "kid", privateKeyId },
    { "alg", "RS256" },
    { "typ", "JWT" }
};

3( 您的 JWT 有效负载不包含范围。我不确定您需要哪个范围,但这里有一个例子。在创建 JWT 之前,将其添加到有效负载:

string scope = "https://www.googleapis.com/auth/cloud-platform";
    var payload = new Dictionary<string, object>
    {
        {"scope", scope},
        {"iss", emailClient},
        {"sub", emailClient},
        {"aud", dialogueFlowServiceApi},
        {"iat", nowDataTime},
        {"exp", oneHourFromNow}
    };

4(对于大多数Google API(不是全部(,您还需要将签名的JWT换成Google OAuth访问令牌:

public static string AuthorizeToken(string token, string auth_url)
{
        var client = new WebClient();
        client.Encoding = Encoding.UTF8;
        var content = new NameValueCollection();
        // Request a "Bearer" access token
        content["assertion"] = token;
        content["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer";
        var response = client.UploadValues(auth_url, "POST", content);
        return Encoding.UTF8.GetString(response);
}

上述授权 URL:

string auth_url = "https://www.googleapis.com/oauth2/v4/token";