Сгенерированный веб-токен JSON не принимается службой API Google. - PullRequest
0 голосов
/ 23 июня 2019

Я создал учетную запись службы и загрузил свои учетные данные JSON в Google Cloud Platform. Мне нужно сделать вызов REST POST в .NET для API службы DialogFlow. На данный момент я могу сделать это только с помощью сгенерированного токена в PowerShell. Поскольку мне нужно сделать все это из сценария, мне нужно сгенерировать JWT, чтобы он передавался в качестве носителя в моем вызове REST. Моя проблема в том, что сгенерированный JWT не учитывается Google.

Я получаю свой ответ в 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 в качестве ключа API службы dialogFlow.

Я ожидаю, что мой сгенерированный JWT будет принят, однако он отклонен Google.

1 Ответ

2 голосов
/ 23 июня 2019

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) Для большинства API Google (не для всех) вам также необходимо обменять подписанный 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";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...