我已经创建了一个服务帐户,并将我的JSON凭证下载到了Google Cloud Platform。我需要在.NET中对DialogFlow Service API进行REST POST调用。目前,我只能使用PowerShell中生成的令牌来做到这一点。由于我需要通过脚本完成所有操作,因此需要生成一个JWT作为REST调用中的承载传递。我的问题是生成的JWT不被Google认可。
我在PowerShell中基于此doc page得到了响应,并从此doc page复制了示例代码以创建我的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;
}
请注意,就像Google在Java sample snippet中所做的那样,需要通过传递公钥和私钥在RSA256中对其进行签名,但是,当我使用.Net时,等效的.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被接受,但是Google拒绝了它。
答案 0 :(得分:2)
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(不是全部),您还需要将Signed 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);
}
上述授权网址:
string auth_url = "https://www.googleapis.com/oauth2/v4/token";