使用OAuth 2和服务帐户访问旧的GData API(电子表格API)

时间:2012-12-01 23:14:38

标签: c# .net oauth-2.0 gdata-api google-spreadsheet-api

简短的问题是这是否可能,如果可能,怎么做?

概要

我有一个.NET应用程序,目前使用服务帐户使用Google Drive API访问Google Apps域中的信息。这可以使用google-api-dotnet-client library和相同行as shown in the samples here的代码正常工作 - 这是我正在做的非常好的基本示例。

我现在要做的是将它扩展到{new} google-api-dotnet-client库的using those APIs provided,它使用较旧的“GData”库,如通过 较早的google-gdata library,特别是Spreadsheets API(可能还有更多)。

问题

这就是出现困难的地方。前一个库完全符合我的要求,正如上面第一段中的第二个链接所证明的那样 - 以及我自己做它的事实。 HOWEVER ...虽然第二个库已更新为支持OAuth 2.0以及其他旧的auth技术,但它没有 - 据我所知,广泛的Google搜索和跟踪 - 和 - 错误 - 允许我需要的“代表我所有用户的服务帐户”操作。

我的问题是我是否遗漏了一些东西(可能很难找到或没有记载的东西),这些东西可以让我做我想做的事。如果不这样做,有什么方法可以强迫这种行为并使这两个库并排运行?

理想的解决方案

理想情况下,我希望某种方式让Google.GData.Spreadsheets.SpreadsheetsService实例能够利用我已经使用的Google.Apis.Authentication.Auth2Authenticator<AssertionFlowClient>实例......不知何故。这种巫术有可能吗?我错过了那个显而易见的东西吗?

如果做不到这一点,我很高兴再次开始使用整个OAuth2“断言流客户端”舞蹈,如果必须的话,以旧版本的库可以处理。

帮助?

其他想法

我已经考虑过 - 暂时拒绝 - 选择从头开始编写我自己的库来实现这一目标。这有两个原因:

  1. gdata库已经存在,并且已经被很多人开发,可能比我自己聪明。我不是那么傲慢,我相信我能做得更好。
  2. 我不确定这些旧版API是否支持/允许使用服务帐户方法的OAuth2。
  3. 我一直希望避免但可能不得不依赖于此处的答案的另一种方法是使用2脚OAuth 1.0来实现这一点。我宁愿不这样做,因为应用程序的某些部分依赖于一种旧的auth方法,而其他部分则使用这种新方式对我来说感觉不对。而且还有更多的问题......


    更新

    我已经考虑过继承GDataRequestFactory和GDataRequest的可能性,所以我可以创建自己的请求工厂,然后使用Google.Apis.Authentication.Auth2Authenticator<AssertionFlowClient>的实例(好吧,无论如何都是Google.Apis.Authentication.IAuthenticator的实例)在调用之前对请求进行身份验证。但是...... GDataRequest的构造函数是内部的,这阻止了我。

    看起来真的不是这样的。

3 个答案:

答案 0 :(得分:20)

为了遇到这个问题的其他人(现在在接受的答案中链接的解决方案使用了弃用的代码),这就是我如何解决它:

首先,开始使用&#34;新API&#34;通过在Google Service Account example之后设置Google.Apis.Auth来使用ServiceAccountCredential nuget包:

//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 = "12345697-abcdefghijklmnop@developer.gserviceaccount.com";

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&#34; land(使用Google.GData.Spreadsheets nuget包)。首先构建SpreadsheetsService(类似于Google&#39; s example):

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&#39; RequestFactory属性设置为此新工厂:

service.RequestFactory = requestFactory;

继续使用SpreadsheetsService,就像使用任何其他技术进行身份验证一样。 (提示:通过邀请serviceAccountEmail地址与工作表共享电子表格)

答案 1 :(得分:4)

我设法通过继承GDataRequestFactory并创建我自己的GDataRequest实现的接口实现来解决这个问题。此实现包含通过反射实例化的GDataRequest实例,并添加必要的代码以使用IAuthenticator的实例(在我的示例中为Auth2Authenticator)执行身份验证。

我写了一篇关于它的博客文章并添加了一个例子作为Gist:

如果有帮助(BSD许可证),请随意使用。

答案 2 :(得分:3)

嘿嘿只是遇到了同样的问题并产生了不同的解决方案:

有没有人想过将credentials-object中的参数直接写入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;
    }
}