Google.GData.Client.GDataRequestException - аутентификация неожиданно завершается неудачей в старом коде

При попытке аутентификации и доступа к электронной таблице на диске Google я получаю следующее исключение:

Необработанное исключение: Google.GData.Client.GDataRequestException: Выполнение запроса автоматической подгонки результата: 404        в Google.GData.Client.Utilities.getAuthException(токены TokenCollection, Ответ Htt pWebResponse)        в Google.GData.Client.Utilities.QueryClientLoginToken(GDataCredentials gc, S tring serviceName, String applicationName, Boolean fUseKeepAlive, IWebProxy prox yServer, Uri clientLoginHandler)        в Google.GData.Client.GDataGAuthRequest.QueryAuthToken(GDataCredentials дс)        в Google.GData.Client.GDataGAuthRequest.EnsureCredentials()        в Google.GData.Client.GDataRequest.EnsureWebRequest()        в Google.GData.Client.GDataGAuthRequest.EnsureWebRequest()        в Google.GData.Client.GDataRequest.Execute()        в Google.GData.Client.GDataGAuthRequest.Execute(Int32 retryCounter)        в Google.GData.Client.GDataGAuthRequest.Execute()        в Google.GData.Client.Service.Query(Uri queryUri, DateTime ifModifiedSince, String etag, Int64 & contentLength)        в Google.GData.Client.Service.Query(FeedQuery feedQuery)        в Google.GData.Documents.DocumentsService.Query(DocumentsListQuery feedQuery)        в GoogleLogger.GoogleService.getLastXECLogRows(String folderName, String имя_файла, строки Int32)

Это код, который работает в течение двух лет без каких-либо проблем. Сначала я подумал, что у меня могут быть права доступа на мою производственную систему, но Google-накопитель загружается в моем веб-браузере. Пробовал это на нескольких других системах, и я получаю то же самое.

Они что-то изменили в Google API сегодня? Это не может быть совпадением!

Ответы

Ответ 1

Google удалил свой старый API проверки подлинности. Вместо этого следует использовать OAuth 2.0.

Я потратил слишком много времени на то, чтобы выяснить, как использовать новый API Auth с более старым API GData, захватывающим биты и фрагменты информации здесь и там из Интернета. Я решил поделиться всеми подробностями со скриншотами, чтобы сэкономить ваше время.

enter image description here

  1. Создать проект. Введите имя.

enter image description here

  1. Перейдите к API & Auth > Credentials и нажмите кнопку Create new Client ID. Он автоматически создаст ключ JSON для вас - проигнорируйте это.

enter image description here

  1. Хит Generate new P12 key

enter image description here

  1. Загрузка файла начнется автоматически. Помните пароль, вам нужно будет открыть файл, который вы только что загрузили.

enter image description here

  1. Переименуйте загруженный файл в Key.p12 и добавьте его в свое решение. Убедитесь, что вы установили соответственно Build Action и Copy to Output Directory.

enter image description here

  1. Установите API Google API с помощью Nuget. В консоли диспетчера пакетов введите следующее:

    Install-Package Google.Apis.Auth
    

enter image description here

  1. Скопируйте адрес электронной почты учетной записи службы, сгенерированный на шаге 4.

enter image description here

  1. Предоставьте соответствующее разрешение этому пользователю в Google Таблице.

  2. Используйте следующий код для запроса электронной таблицы. Замените адрес электронной почты и адрес электронной таблицы Google в коде ниже.

    const string ServiceAccountEmail = "[email protected]ount.com";
    
    var certificate = new X509Certificate2("Key.p12", "notasecret", X509KeyStorageFlags.Exportable);
    
    var serviceAccountCredentialInitializer = 
        new ServiceAccountCredential.Initializer(ServiceAccountEmail)
        {
            Scopes = new[] { "https://spreadsheets.google.com/feeds" }
        }.FromCertificate(certificate);
    
    var credential = new ServiceAccountCredential(serviceAccountCredentialInitializer);
    
    if (!credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Result)
        throw new InvalidOperationException("Access token request failed.");
    
    var requestFactory = new GDataRequestFactory(null);
    requestFactory.CustomHeaders.Add("Authorization: Bearer " + credential.Token.AccessToken);
    
    var service = new SpreadsheetsService(null) { RequestFactory = requestFactory };
    
    var query = new ListQuery("https://spreadsheets.google.com/feeds/list/0ApZkobM61WIrdGRYshh345523VNsLWc/1/private/full");
    var feed = service.Query(query);
    
    var rows = feed.Entries
        .Cast<ListEntry>()
        .Select(arg =>
            new
            {
                Field0 = arg.Elements[0].Value,
                Field1 = arg.Elements[1].Value
            })
        .ToList();
    

Ответ 2

Мне удалось решить эту проблему, используя это решение с учетной записью службы с oAuth2.0 Доступ к старым API-интерфейсам GData (API-интерфейсам таблиц) с использованием OAuth 2 и учетной записи службы

Решение: 1. Создайте учетную запись Project и Google Service в https://console.developers.google.com/project

  1. Создайте свой ключ p12.
  2. Разрешить API-интерфейсы в консоли разработчика, которые вы хотите использовать (в основном мы собираемся использовать старый API, поэтому вы можете пропустить этот шаг, но на всякий случай)
  3. Используйте приведенный ниже код (.NET Framework 4.5!)
  4. Также не забудьте предоставить "[email protected]" доступ к вашему документу электронной таблицы, поскольку вы предоставляете разрешения для обычных пользователей, нажав "Поделиться".

код:

using System.Security.Cryptography.X509Certificates;
using Google.GData.Client;
using Google.GData.Extensions;
using Google.GData.Spreadsheets;
using Google.Apis.Auth.OAuth2;

string keyFilePath = @"C:\key.p12";    // found in developer console
string serviceAccountEmail = "[email protected]";   // found in developer console
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);

ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) //create credential using certificate
        {
            Scopes = new[] { "https://spreadsheets.google.com/feeds/" } //this scopr is for spreadsheets, check google scope FAQ for others
        }.FromCertificate(certificate));

credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait(); //request token

var requestFactory = new GDataRequestFactory("Some Name"); 
requestFactory.CustomHeaders.Add(string.Format("Authorization: Bearer {0}", credential.Token.AccessToken));

SpreadsheetsService myService = new SpreadsheetsService("You App Name"); //create your old service
myService.RequestFactory = requestFactory; //add new request factory to your old service

SpreadsheetQuery query = new SpreadsheetQuery(); //do the job as you done it before
SpreadsheetFeed feed = myService.Query(query);

Ответ 3

Хорошо, я понял это. Пошаговые инструкции следуют ниже: см. Также код, приведенный ниже. FYI, это работает в .Net 3.5 и в отличие от предлагаемого ранее решения нет новых зависимостей. Вы должны быть в рабочем состоянии в кратчайшие сроки.

  • Если вы еще не создали свои учетные данные OAuth 2.0, я предполагаю, что вы уже знаете, как их получить, но здесь:

    a) Войдите в консоль разработчика Google: http://console.developers.google.com б) Создать проект c) Создайте свои учетные данные - используйте 'установленное приложение' d) добавьте необходимые API-интерфейсы - я думаю, что API-интерфейс Драйвера определенно требуется. Я также добавил Drive SDK на всякий случай.

  • Скопируйте приведенный ниже код в VS и отредактируйте первый метод Main() с помощью вашего ключа клиента и секретного ключа.

  • Запустите приложение и скопируйте как новый токен доступа, так и токен обновления. Поместите эти и оставшиеся учетные данные во второй метод Main() ниже.

  • Теперь вы сможете запустить второй метод Main() (просто отмените именование). Отныне это будет все, что вам нужно - нет необходимости повторно запускать первый метод Main().

BTW, первый метод Main() приведен ниже: https://developers.google.com/google-apps/spreadsheets/authorize

Я добавил, однако, и тип отсутствующего токена, а также тип доступа. Это необходимо, поэтому используйте следующий код:

using System;
using Google.GData.Client;
using Google.GData.Spreadsheets;
using Google.GData.Documents;
using System.Configuration;
using System.Collections.Specialized;

namespace GoogleSpreadsheet
{
  class GoogleOAutho2
  {

    private static String folderName = "crazy.ivan";


    static void Main(string[] args)
    {
      ////////////////////////////////////////////////////////////////////////////
      // STEP 1: Configure how to perform OAuth 2.0
      ////////////////////////////////////////////////////////////////////////////

      // TODO: Update the following information with that obtained from
      // https://code.google.com/apis/console. After registering
      // your application, these will be provided for you.

      string CLIENT_ID = "your_client_id";

      // This is the OAuth 2.0 Client Secret retrieved
      // above.  Be sure to store this value securely.  Leaking this
      // value would enable others to act on behalf of your application!
      string CLIENT_SECRET = "your_secret_key"

      // Space separated list of scopes for which to request access.
      string SCOPE = "https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds https://docs.google.com/feeds";

      // This is the Redirect URI for installed applications.
      // If you are building a web application, you have to set your
      // Redirect URI at https://code.google.com/apis/console.
      string REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";

      string TOKEN_TYPE = "refresh";

      ////////////////////////////////////////////////////////////////////////////
      // STEP 2: Set up the OAuth 2.0 object
      ////////////////////////////////////////////////////////////////////////////

      // OAuth2Parameters holds all the parameters related to OAuth 2.0.
      OAuth2Parameters parameters = new OAuth2Parameters();

      // Set your OAuth 2.0 Client Id (which you can register at
      // https://code.google.com/apis/console).
      parameters.ClientId = CLIENT_ID;

      // Set your OAuth 2.0 Client Secret, which can be obtained at
      // https://code.google.com/apis/console.
      parameters.ClientSecret = CLIENT_SECRET;

      // Set your Redirect URI, which can be registered at
      // https://code.google.com/apis/console.
      parameters.RedirectUri = REDIRECT_URI;

      ////////////////////////////////////////////////////////////////////////////
      // STEP 3: Get the Authorization URL
      ////////////////////////////////////////////////////////////////////////////

      // Set the scope for this particular service.
      parameters.Scope = SCOPE;

      parameters.AccessType = "offline"; // IMPORTANT and was missing in the original

      parameters.TokenType = TOKEN_TYPE; // IMPORTANT and was missing in the original


      // Get the authorization url.  The user of your application must visit
      // this url in order to authorize with Google.  If you are building a
      // browser-based application, you can redirect the user to the authorization
      // url.
      string authorizationUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
      Console.WriteLine(authorizationUrl);
      Console.WriteLine("Please visit the URL above to authorize your OAuth "
        + "request token.  Once that is complete, type in your access code to "
        + "continue...");
      parameters.AccessCode = Console.ReadLine();

      ////////////////////////////////////////////////////////////////////////////
      // STEP 4: Get the Access Token
      ////////////////////////////////////////////////////////////////////////////

      // Once the user authorizes with Google, the request token can be exchanged
      // for a long-lived access token.  If you are building a browser-based
      // application, you should parse the incoming request token from the url and
      // set it in OAuthParameters before calling GetAccessToken().
      OAuthUtil.GetAccessToken(parameters);
      string accessToken = parameters.AccessToken;
      string refreshToken = parameters.RefreshToken;
      Console.WriteLine("OAuth Access Token: " + accessToken + "\n");
      Console.WriteLine("OAuth Refresh Token: " + refreshToken + "\n");

      ////////////////////////////////////////////////////////////////////////////
      // STEP 5: Make an OAuth authorized request to Google
      ////////////////////////////////////////////////////////////////////////////

      // Initialize the variables needed to make the request
      GOAuth2RequestFactory requestFactory =
          new GOAuth2RequestFactory(null, "MySpreadsheetIntegration-v1", parameters);
      SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");
      service.RequestFactory = requestFactory;

      // Make the request to Google
      // See other portions of this guide for code to put here...

      // Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
      Google.GData.Spreadsheets.SpreadsheetQuery query = new Google.GData.Spreadsheets.SpreadsheetQuery();

      // Make a request to the API and get all spreadsheets.
      SpreadsheetFeed feed = service.Query(query);

      // Iterate through all of the spreadsheets returned
      foreach (SpreadsheetEntry entry in feed.Entries)
      {
        // Print the title of this spreadsheet to the screen
        Console.WriteLine(entry.Title.Text);
      }
      Console.ReadLine();

     }


    // once you copied your access and refresh tokens
    // then you can run this method directly from now on...
    static void MainX(string[] args)
    {
    GOAuth2RequestFactory requestFactory = RefreshAuthenticate();

         SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");  
         service.RequestFactory = requestFactory;

      // Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
      Google.GData.Spreadsheets.SpreadsheetQuery query = new Google.GData.Spreadsheets.SpreadsheetQuery();

      // Make a request to the API and get all spreadsheets.
      SpreadsheetFeed feed = service.Query(query);

      // Iterate through all of the spreadsheets returned
      foreach (SpreadsheetEntry entry in feed.Entries)
      {
        // Print the title of this spreadsheet to the screen
        Console.WriteLine(entry.Title.Text);
      }
      Console.ReadLine();



    public static GOAuth2RequestFactory RefreshAuthenticate() {
        OAuth2Parameters parameters = new OAuth2Parameters(){
            RefreshToken = "the_refresh_token_you_copied_from_the_CLI_running_the_first_method";
            AccessToken = "the_access_token_you_copied_from_the_CLI_running_the_first_method";
            ClientId = "your_client_id";
            ClientSecret = "your_dirty_little_secret";
            Scope = "https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds",
            AccessType = "offline",
            TokenType = "refresh"
        };
        string authUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
        return new GOAuth2RequestFactory(null, "evilspeculator", parameters);
    }
  }
}

Надеюсь, что это сработает для вас, ребята - удачи!

Ответ 4

Andrew Мне было интересно, как вы получили dll google.apis.auth.oauth2. Я пытаюсь внедрить ваше исправление, и я не могу найти правильный способ установки библиотеки.

Мне кажется, что я смогу заставить это работать после того, как у меня есть эта часть.