tutorial sheets sheet google example c# .net oauth-2.0 gdata-api google-spreadsheet-api

c# - sheets - Acceso a las API de GData(API de hoja de cálculo) más antiguas mediante OAuth 2 y una cuenta de servicio



google spreadsheet api javascript (3)

Logré resolver esto subclasificando GDataRequestFactory y creando mi propia implementación de las interfaces implementadas por GDataRequest. Esta implementación ajusta una instancia de GDataRequest instanciada a través de la reflexión, y agrega el código necesario para realizar la autenticación utilizando una instancia de IAuthenticator (en mi caso, Auth2Authenticator).

Escribí una publicación de blog en él y agregué un ejemplo como una Gist:

Siéntase libre de usar esto si le ayuda (licencia BSD).

La pregunta corta es si esto es posible y, de ser así, ¿cómo?

contorno

Tengo una aplicación .NET que actualmente utiliza una cuenta de servicio para acceder a la información en un dominio de Google Apps mediante la API de Google Drive. Esto funciona bien usando la biblioteca de google-api-dotnet-client y el código siguiendo las mismas líneas que se muestran en las muestras aquí , que actualmente son un buen ejemplo básico de lo que estoy haciendo.

Lo que quiero hacer ahora es extenderlo así como usar las API proporcionadas por la "nueva" biblioteca de google-api-dotnet-client, utiliza las bibliotecas más antiguas "GData", tal como se proporciona a través de la biblioteca más antigua de google-gdata. , específicamente la API de hojas de cálculo (y quizás más por venir).

El problema

Aquí es donde surge la dificultad. La biblioteca anterior hace exactamente lo que quiero, como lo demuestra el segundo enlace en el primer párrafo anterior, y el hecho de que lo haga yo mismo. SIN EMBARGO ... aunque la segunda biblioteca se ha actualizado para admitir OAuth 2.0 además de OAuth 1.0 y las otras técnicas de autenticación más antiguas, no lo permite, por lo que puedo decir de las extensas búsquedas en Google y rastro y error, permite el " Cuenta de servicio en nombre de la operación de todos mis usuarios que necesito.

Mi pregunta es si me estoy perdiendo algo (posiblemente algo difícil de encontrar o algo no documentado) que me permita hacer lo que quiero. Si eso falla, ¿hay alguna manera de forzar este comportamiento y hacer que estas dos bibliotecas operen en paralelo?

La solucion ideal

Idealmente, me encantaría tener alguna forma de que la instancia de Google.GData.Spreadsheets.SpreadsheetsService pudiera aprovechar la instancia de Google.GData.Spreadsheets.SpreadsheetsService Google.Apis.Authentication.Auth2Authenticator<AssertionFlowClient> que ya estoy usando ... de alguna manera. ¿Es posible tal brujería? Me estoy perdiendo lo obvio?

Si eso falla, me alegro de volver a hacer el baile completo del "cliente de flujo de afirmación" de OAuth2 si es necesario, de alguna manera que la biblioteca más antigua pueda manejar.

¿Ayuda?

otros pensamientos

He considerado, y por el momento he rechazado, la opción de empezar de cero y escribir mi propia biblioteca para que esto suceda. Esto es por dos razones:

  1. La biblioteca gdata ya existe, y ha sido desarrollada por muchas personas probablemente más inteligentes que yo. No soy tan arrogante que creo que puedo hacerlo mejor.
  2. No estoy seguro de que el enfoque OAuth2 con cuenta de servicio sea compatible / permitido incluso en estas API anteriores.

Un enfoque alternativo que he estado esperando evitar pero que podría tener que recurrir a las respuestas aquí será usar OAuth 1.0 de dos patas para partes de esto. Preferiría no hacerlo, ya que tener partes de la aplicación se basan en un método de autenticación antiguo mientras que otras partes lo hacen de la mejor manera que me parece mal. Y hay mucho más para salir mal ...

Actualizaciones

He considerado la posibilidad de subclasificar GDataRequestFactory y GDataRequest para poder hacer mi propia fábrica de solicitudes y hacer que tome la instancia de Google.Apis.Authentication.Auth2Authenticator<AssertionFlowClient> (bueno, una instancia de Google.Apis.Authentication.IAuthenticator todos modos) que podría intervenir para autenticar la solicitud justo antes de que se llame. Sin embargo ... el constructor para GDataRequest es interno, lo que me ha detenido.

Realmente parece que esto no está destinado a ser.


Oye, simplemente tropezé con el mismo problema y encontré una solución diferente:

¿Alguien ha pensado alguna vez en escribir los parámetros del objeto credenciales directamente en un objeto OAuth2Parameters?

Hice esto y funcionó muy bien:

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; } }


Por el bien de otras personas que se encuentran con esta pregunta (ahora que la solución vinculada a la respuesta aceptada utiliza un código en desuso), así lo resolví:

Primero, comience en "new API API" (use el paquete nuget Google.Apis.Auth) configurando un ServiceAccountCredential siguiendo el ejemplo de la cuenta de servicio de 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));

Indique la credencial para solicitar un token de acceso:

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

Ahora es el momento de volver a la tierra "antigua API" (use el paquete de Google.GData.Spreadsheets Google.GData.Spreadsheets). Comience por construir el SpreadsheetsService (similar al example de Google):

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

Para usar la autenticación de la cuenta de servicio, crearemos una instancia de GDataRequestFactory y estableceremos un encabezado de Authorization personalizado:

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

Finalmente, establezca la propiedad RequestFactory SpreadsheetsService en esta nueva fábrica:

service.RequestFactory = requestFactory;

Y siga adelante y use el Servicio de SpreadsheetsService como lo habría autenticado utilizando cualquier otra técnica. ( Sugerencia: comparta hojas de cálculo con la cuenta de servicio invitando a la dirección de serviceAccountEmail electrónico de cuenta de servicio)