Сбой Dialogflow Rest API «Авторизация учетной записи службы без OAuth» - PullRequest
1 голос
/ 28 мая 2019

Я настраиваю удаленный сервер и хотел бы вызвать Dialogflow REST API и, в частности, определить намеренный API.

У меня уже есть агент, настроенный со всеми намерениями и сущностями, и я хотел бы получить доступ к намерениям удаленно. Я читал о том, как интегрироваться с API, и в этой статье я встречал «Приложение: авторизация учетной записи службы без OAuth»

https://developers.google.com/identity/protocols/OAuth2ServiceAccount

Полагаю, я в значительной степени следовал всем инструкциям. Что я мог сделать неправильно или я пропал?

Вот мой код:

    public class DetectIntentTest {

    private static final String PROJECTID = "myprojectid-****";
    private static final String OAUTH_TOKEN_URI = "https://oauth2.googleapis.com/token";
    private static final String CREDENTIALSFILE = "mycredentialsfile-****-****.json";
    private static final String JWT_BEARER_TOKEN_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer";
    private static final HttpTransport HTTPTRANSPORT = new NetHttpTransport();

public static HttpRequest buildRequest(boolean withoutOauth, String url, String message) throws Exception {
    ServiceAccountCredentials credentials = fetchCredentials();
    String jwt = createJwt(withoutOauth, credentials);
    if (jwt == null) {
        throw new Exception("Could not create a signed jwt token");
    }

    String token = withoutOauth ? jwt : fetchToken(jwt);
    if (token == null) {
        throw new Exception("Could not to retrieve token");
    }

    return HTTPTRANSPORT.createRequestFactory()
            .buildPostRequest(
                    new GenericUrl(url),
                    new JsonHttpContent(JacksonFactory.getDefaultInstance(), message))
            .setHeaders(new HttpHeaders()
                    .setAuthorization("Bearer " + token)
                    .set("Host", host));
}

public static String buildUrl(String uri, String api, String languageCode, String projectId, String sessionId) {
    return "https://dialogflow.googleapis.com/v2/projects/" + projectId + uri + sessionId + ":" + api;
}

 private static String createJwt(boolean withoutOauth, ServiceAccountCredentials credentials) throws Exception {
    long now = System.currentTimeMillis();
    String clientId = credentials.getClientId();
    String privateKeyId = credentials.getPrivateKeyId();
    String serviceAccount = credentials.getClientEmail();
    String oauthTokenURI = credentials.getTokenServerUri().toString();
    RSAPrivateKey privateKey = (RSAPrivateKey) credentials.getPrivateKey();
    Algorithm algorithm = Algorithm.RSA256(null, privateKey);
    return withoutOauth
            ? JWT.create()
                    .withKeyId(privateKeyId)
                    .withIssuer(serviceAccount)
                    .withSubject(serviceAccount)
                    .withIssuedAt(new Date(now))
                    .withExpiresAt(new Date(now + 3600 * 1000L))
                    .withAudience("https://dialogflow.googleapis.com/google.cloud.dialogflow.v2.Agents")
                    .sign(algorithm)
            : JWT.create()
                    .withKeyId(privateKeyId)
                    .withIssuer(serviceAccount)
                    .withSubject(serviceAccount)
                    .withIssuedAt(new Date(now))
                    .withExpiresAt(new Date(now + 3600 * 1000L))
                    .withAudience(oauthTokenURI)
                    .withClaim("target_audience", clientId)
                    .sign(algorithm);
}

public static ServiceAccountCredentials fetchCredentials() throws Exception {
    File credentialFile = new File(ClassLoader.getSystemResource(CREDENTIALSFILE).getFile());
    ServiceAccountCredentials credentials = ServiceAccountCredentials
            .fromStream(new FileInputStream(credentialFile));
    credentials.createScoped(
            "https://www.googleapis.com/auth/dialogflow",
            "https://www.googleapis.com/auth/cloud-platform");
    return credentials;
}

public static String fetchToken(String jwt) throws Exception {
    final GenericData tokenRequest = new GenericData().set("grant_type", JWT_BEARER_TOKEN_GRANT_TYPE).set("assertion", jwt);
    final UrlEncodedContent content = new UrlEncodedContent(tokenRequest);
    final HttpRequestFactory requestFactory = HTTPTRANSPORT.createRequestFactory();
    final HttpRequest request = requestFactory
            .buildPostRequest(new GenericUrl(OAUTH_TOKEN_URI), content)
            .setParser(new JsonObjectParser(JacksonFactory.getDefaultInstance()));
    HttpResponse response = request.execute();
    GenericData responseData = response.parseAs(GenericData.class);
    return (String) responseData.get("id_token");
}

public static void main(String[] args) {

    String api = "detectIntent";
    String uri = "/agent/sessions/";
    String languageCode = "en-US";
    String text = "Hi I would like help";
    String sessionId = UUID.randomUUID().toString();
    String host = "https://dialogflow.googleapis.com";
    String url = DetectIntentTest.buildUrl(uri, api, languageCode, PROJECTID, sessionId);
    JSONObject message = new JSONObject("{"
            + "  \"queryInput\": {"
            + "    \"text\": {"
            + "      \"languageCode\": \"" + languageCode + "\","
            + "      \"text\": \"" + text + "\""
            + "    }"
            + "  }"
            + "}");
    try {
        HttpRequest request = DetectIntentTest.buildRequest(true,host, url, message.toString());
        HttpResponse response = request.execute();
        System.out.println(response.getStatusCode());
        System.out.println(response.getStatusMessage());
        GenericData responseData = response.parseAs(GenericData.class);
        System.out.println(responseData.toString());
    } catch (Exception ex) {
        Logger.getLogger(DetectIntentTest.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
}

Переменные:

    {
"bearerToken": "eyJraWQiOiIxYWEyY2MzYTQwZjUwZT********",

"host": "https://dialogflow.googleapis.com",

"text": "Hi I would like help",

"languageCode": "en-US",

"projectId": "myprojectid-****",

"url": "https://dialogflow.googleapis.com/v2/projects/myprojectid-****/agent/sessions/4a02046c-c1a2-4a35-b680-6e779c6d34b8:detectIntent"
    }

Тело:

    {"queryInput": 
     {"text":
       {"text": "Hi I would like help",
        "languageCode": "en-US"
       }
      }
     }

Запрос:

    Request{
    method=POST, 
    url=https://dialogflow.googleapis.com/v2/projects/myprojectid-****/agent/sessions/4a02046c-c1a2-4a35-b680-6e779c6d34b8:detectIntent, 
    tags={}
    }

Заголовки:

    Authorization: Bearer eyJraWQiOiIxYWEyY2MzYTQwZjUwZT********
    Host: https://dialogflow.googleapis.com
    Content-Type: application/json; charset=utf-8

Выход:

    com.google.api.client.http.HttpResponseException: 401 Unauthorized 

1 Ответ

1 голос
/ 29 мая 2019

Я обнаружил проблему, я использовал неправильное имя API для определения цели в аудитории JWT в этом списке.Правильное имя API - "google.cloud.dialogflow.v2.Sessions"

https://github.com/googleapis/googleapis/blob/master/google/cloud/dialogflow/dialogflow_v2.yaml

...