Google Диск /OAuth - не удается выяснить, как получить повторно используемые GoogleCredentials

Я успешно установил и запустил приложение быстрого запуска Google Диска под названием DriveCommandLine. Я также немного адаптировал его для получения информации о файле для одного из файлов в моей учетной записи накопителя.

Теперь я хочу сохранить учетные данные и повторно использовать их без необходимости посещать веб-страницу каждый раз, чтобы получить код авторизации. Я проверил эту страницу с инструкциями по извлечению и использованию учетных данных OAuth 2.0. Чтобы использовать класс example (MyClass), я изменил строку в DriveCommandLine, где создается экземпляр объекта Credential:

Credential credential = MyClass.getCredentials(code, "");

В результате возникает следующее исключение:

java.lang.NullPointerException
    at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:187)
    at com.google.api.client.json.jackson.JacksonFactory.createJsonParser(JacksonFactory.java:84)
    at com.google.api.client.json.JsonFactory.fromInputStream(JsonFactory.java:247)
    at com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.load(GoogleClientSecrets.java:168)
    at googledrive.MyClass.getFlow(MyClass.java:145)
    at googledrive.MyClass.exchangeCode(MyClass.java:166)
    at googledrive.MyClass.getCredentials(MyClass.java:239)
    at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
    at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)

Я просматриваю эти API (Google Диск и OAuth) уже 2 дня и добился очень большого прогресса. Я бы очень признателен за помощь в вышеупомянутой ошибке и проблеме получения постоянных учетных данных в целом.

Вся эта структура кажется мне излишне сложной. Кто-нибудь хочет объяснить, почему я не могу просто создать простой объект Credential, передав свое имя пользователя и пароль Google?

Спасибо, Брайан О Кэрролл, Дублин, Ирландия

* Обновление *

Хорошо, я только что обошел вышеупомянутую ошибку, и теперь у меня есть новая.

То, как я столкнулся с первой проблемой, - это изменить MyClass.getFlow(). Вместо того, чтобы создавать объект GoogleClientServices из json файла, я использовал другую версию GoogleAuthorizationCodeFlow.Builder, которая позволяет вам вводить идентификатор клиента и секрет клиента непосредственно в виде строк:

flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, "<MY CLIENT ID>", "<MY CLIENT SECRET>", SCOPES).setAccessType("offline").setApprovalPrompt("force").build();

Теперь проблема заключается в том, что я получаю следующую ошибку, когда пытаюсь использовать поток (объект GoogleAuthorizationCodeFlow) для обмена авторизационным кодом для объекта Credentials:

An error occurred: com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
  "error" : "invalid_scope"
}
googledrive.MyClass$CodeExchangeException
        at googledrive.MyClass.exchangeCode(MyClass.java:185)
        at googledrive.MyClass.getCredentials(MyClass.java:262)
        at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
        at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)

Есть ли какая-то другая область, которую я должен использовать для этого? В настоящее время я использую массив областей с MyClass:

private static final List<String> SCOPES = Arrays.asList(
        "https://www.googleapis.com/auth/drive.file",
        "https://www.googleapis.com/auth/userinfo.email",
        "https://www.googleapis.com/auth/userinfo.profile");

Спасибо!

Ответ 1

Я чувствую твою боль. Я два месяца и все еще удивляюсь.

Некоторые из моих исследований...

  • Когда вы запрашиваете разрешения пользователя, укажите "offline = true". Это будет (иногда "sic" ) возвращает refreshtoken, что равнозначно паролю с ограниченными разрешениями. Вы можете сохранить это и повторно использовать его в любое время (пока пользователь не аннулирует его), чтобы получить токен доступа.

  • Я чувствую, что SDK Google являются скорее препятствием, чем помощью. Один за другим я прекратил их использовать и теперь напрямую вызываю REST API.

  • В последнем пункте вы можете (просто) использовать протокол Google clientlogin для доступа к API предыдущего поколения. Однако это полностью устарело и вскоре будет отключено. OAuth предназначен для мелкозернистого контроля авторизации, которая по своей сути сложна. Поэтому, хотя я согласен, что это сложно, я не думаю, что это излишне. Мы живем в сложном мире: -)

Ваши и мои опыты показывают, что сообщество разработчиков все еще нуждается в сводном документе и рецептах, чтобы получить этот материал в наши зеркала заднего вида, чтобы мы могли сосредоточиться на задаче.

Ответ 2

Oath2Scopes импортируется следующим образом:

import com.google.api.services.oauth2.Oauth2Scopes;

Для доступа к этому пакету вам необходимо предоставить файл jar 'google-api-services-oauth2-v2-rev15-1.8.0-beta.jar' в вашем классе. Его можно загрузить здесь.

Нет, я не знаю, как получить учетные данные, не посещая URL-адрес авторизации хотя бы один раз и копируя код. Я изменил MyClass, чтобы хранить и извлекать учетные данные из базы данных (в моем случае это простая таблица, содержащая userid, accesstoken и refreshtoken). Таким образом, мне нужно только получить код авторизации один раз, и как только я получу токены доступа/обновления, я могу повторно использовать их для создания объекта GoogleCredential. Здесь как Imake объект GoogleCredential:

GoogleCredential credential = new GoogleCredential.Builder().setJsonFactory(jsonFactory)
            .setTransport(httpTransport).setClientSecrets(clientid, clientsecret).build();
    credential.setAccessToken(accessToken);
    credential.setRefreshToken(refreshToken);

Просто введите ваш clientid, clientsecret, accessToken и refreshToken выше.

У меня нет большого количества времени, чтобы отделить и убрать весь мой код, чтобы опубликовать его здесь, но если у вас все еще есть проблемы, сообщите мне, и я посмотрю, что я могу сделать. Хотя, вы действительно просите слепого за указаниями. Мое понимание всей этой системы очень отрывочно!

Cheers, Brian

Ответ 3

Хорошо, я наконец решил вторую проблему выше, и я наконец получил рабочий объект GoogleCredential с токеном доступа и токеном обновления.

Я продолжал пытаться решить проблему с областями, изменив список областей в MyClass (тот, который управляет учетными данными). В конце концов мне нужно было настроить области видимости в моей модифицированной версии DriveCommandLine (той, которая первоначально использовалась для получения кода авторизации). Я добавил 2 области от Oauth2Scopes:

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
    httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET,
    Arrays.asList(DriveScopes.DRIVE, Oauth2Scopes.USERINFO_EMAIL, Oauth2Scopes.USERINFO_PROFILE))
    .setAccessType("offline").setApprovalPrompt("force").build();

Добавление областей для пользовательской информации позволило мне получить идентификатор пользователя позже в MyClass. Теперь я могу использовать идентификатор пользователя для хранения учетных данных в базе данных для повторного использования (без необходимости каждый раз обращаться к URL-адресу). Я также установил тип доступа в "автономный", как было предложено pinoyyid.