Доступ к старым API-интерфейсам GData (API-интерфейсам) с использованием OAuth 2 и учетной записи службы - программирование
Подтвердить что ты не робот

Доступ к старым API-интерфейсам GData (API-интерфейсам) с использованием OAuth 2 и учетной записи службы

Короткий вопрос: возможно ли это, и если да, то как?

Структура

У меня есть приложение .NET, которое в настоящее время использует учетную запись службы для доступа к информации в домене Google Apps с помощью API Google Диска. Это отлично работает с помощью google-api-dotnet-client library и кода в тех же строках как показано в примерах здесь - которые в настоящее время являются очень хорошим базовым примером того, что я делаю.

Теперь я хочу расширить его так же, как используя эти API, предоставленные в "новой" библиотеке google-api-dotnet-client, которая использует более старые библиотеки "GData", как это предусмотрено старше google-gdata library, в частности API таблиц (и, возможно, еще больше).

Проблема

Здесь возникает трудность. Бывшая библиотека делает именно то, что я хочу, о чем свидетельствует вторая ссылка в первом абзаце выше, - и тот факт, что я ее сам делаю. ОДНАКО... хотя вторая библиотека была обновлена ​​для поддержки OAuth 2.0 в дополнение к OAuth 1.0 и другим старым методам auth, это не так, насколько я могу судить по обширным сайтам Googling и trail- и-error - разрешить операцию "учетная запись службы от имени всех моих пользователей", которая мне нужна.

Мой вопрос заключается в том, что я что-то упустил (возможно, трудно найти или не документировал что-то), что позволило бы мне делать то, что я хочу. В противном случае, могу ли я заставить это поведение и заставить эти две библиотеки работать бок о бок?

Идеальное решение

В идеале мне бы хотелось, чтобы экземпляр Google.GData.Spreadsheets.SpreadsheetsService мог использовать экземпляр Google.Apis.Authentication.Auth2Authenticator<AssertionFlowClient>, который я уже использую... как-то. Возможно ли такое колдовство? Я пропущу очевидное?

В противном случае я с удовольствием сделаю весь "клиент потока утверждения" OAuth2 "снова", если мне придется, в некотором роде, справиться с более старой библиотекой.

Справка

Другие мысли

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

  • Библиотека gdata уже существует и была разработана многими людьми, более умными, чем я. Я не настолько высокомерен, что считаю, что могу сделать лучше.
  • Я не уверен, что OAuth2 с подходом к учетной записи службы поддерживается даже на этих более старых API-интерфейсах.

Альтернативный подход, который я надеялся избежать, но, возможно, придется отпасть в зависимости от ответов здесь, будет использовать двухсторонний OAuth 1.0 для части этого. Я бы предпочел не делать этого, поскольку части приложения полагаются на один старый метод auth, в то время как другие части делают это, хороший новый способ просто мне не нравится. И там гораздо больше, чтобы пойти не так...


Обновление

Я рассмотрел возможность подкласса GDataRequestFactory и GDataRequest, чтобы я мог сделать свой собственный запрос factory, и у него есть экземпляр Google.Apis.Authentication.Auth2Authenticator<AssertionFlowClient> (ну, экземпляр Google.Apis.Authentication.IAuthenticator в любом случае), который мог бы выполнить аутентификацию запрос перед его вызовом. Однако... конструктор для GDataRequest является внутренним, что остановило меня.

Это похоже на то, что это не должно быть.

4b9b3361

Ответ 1

Для других людей, сталкивающихся с этим вопросом (теперь, когда решение, связанное с принятым ответом, использует устаревший код), вот как я его решил:

Сначала начните с земли "нового API" (используйте пакет Google.Apis.Auth nuget), настроив ServiceAccountCredential после Google Пример учетной записи службы:

//In the old api, this accessed the main api accounts' sheets, not anymore
//** Important ** share spreadsheets with the Service Account by inviting the "serviceAccountEmail" address to the sheet
string serviceAccountEmail = "[email protected]";

var certificate = new X509Certificate2(@"key.p12", "notasecret", X509KeyStorageFlags.Exportable);

ServiceAccountCredential credential = new ServiceAccountCredential(
   new ServiceAccountCredential.Initializer(serviceAccountEmail)
   {
       Scopes = new[] { "https://spreadsheets.google.com/feeds", "https://docs.google.com/feeds" }
   }.FromCertificate(certificate));

Скажите учетным данным, чтобы запросить токен доступа:

credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait();

Теперь пришло время вернуться на "старый интерфейс API" (используйте пакет Google.GData.Spreadsheets nuget). Начните с построения SpreadsheetsService (похоже на Google пример):

SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");

Чтобы использовать аутентификацию учетной записи службы, мы создадим экземпляр GDataRequestFactory и настроим пользовательский заголовок Authorization:

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

Наконец, установите для свойства SpreadsheetsService RequestFactory этот новый factory:

service.RequestFactory = requestFactory;

И идите и используйте SpreadsheetsService, как и вы, с помощью любой другой техники. ( Подсказка: обмениваются электронными таблицами с учетной записью службы, приглашая адрес serviceAccountEmail на лист)

Ответ 2

Мне удалось решить это путем подкласса GDataRequestFactory и создания моей собственной реализации интерфейсов, реализованных GDataRequest. Эта реализация завершает экземпляр GDataRequest, созданный с помощью отражения, и добавляет в необходимый код для выполнения проверки подлинности с использованием экземпляра IAuthenticator (в моем случае Auth2Authenticator).

Я написал сообщение в блоге и добавил пример как Gist:

Не стесняйтесь использовать это, если это вам поможет (лицензия BSD).

Ответ 3

Эй просто споткнулся по той же проблеме и произвел другое решение:

Кто-нибудь когда-либо обращался к написанию параметров из объекта credentials непосредственно в OAuth2Parameters-Object?

Я сделал это, и он работал красиво:

public class OAuthTest
{  
    OAuth2Parameters param = new OAuth2Parameters();

    public OAuthTest()
    {
        Debug.WriteLine("Calling: AuthGoogleDataInterface()");
        bool init = AuthGoogleDataInterface();
        if (init)
        {
            GOAuth2RequestFactory requestFactory = new GOAuth2RequestFactory(null, "My App User Agent", this.param);
            //requestFactory.CustomHeaders.Add(string.Format("Authorization: Bearer {0}", credential.Token.AccessToken));
            var service = new SpreadsheetsService("MyService");
            service.RequestFactory = requestFactory;
            SpreadsheetQuery query = new 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
                Debug.WriteLine(entry.Title.Text);
            }
        }
        Debug.WriteLine(m_Init);
    }

    private bool AuthGoogleDataInterface()
    {
        bool b_success;
        try
        {
            Console.WriteLine("New User Credential");
            // New User Credential
            UserCredential credential;
            using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
            {
                GoogleClientSecrets GCSecrets = GoogleClientSecrets.Load(stream);
                string[] ArrScope = new[] { "https://spreadsheets.google.com/feeds", "https://docs.google.com/feeds" };
                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GCSecrets.Secrets,
                    ArrScope,
                    "user", CancellationToken.None,
                new FileDataStore("My.cal")).Result;
                // put the Information generated for the credentials object into the OAuth2Parameters-Object to access the Spreadsheets
                this.param.ClientId = GCSecrets.Secrets.ClientId; //CLIENT_ID;
                this.param.ClientSecret = GCSecrets.Secrets.ClientSecret; //CLIENT_SECRET;
                this.param.RedirectUri = "urn:ietf:wg:oauth:2.0:oob"; //REDIRECT_URI;
                this.param.Scope = ArrScope.ToString();
                this.param.AccessToken = credential.Token.AccessToken;
                this.param.RefreshToken = credential.Token.RefreshToken;
            }

            Debug.WriteLine("AuthGoogleDataInterface: Success");
            b_success = true;
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.ToString());
            b_success = false;
        }
        return b_success;
    }
}