5

我大约每 1.5 分钟用我的 C# 应用程序执行一次 Google 应用程序脚本。应用程序脚本在电子表格之间移动内容,并编辑工作表。我也使用 Drive API。

我的脚本在很长一段时间内运行良好,除了我每小时收到 5 分钟的授权错误。

这是我处理授权的代码:

class Authentication
{

    public static ScriptService ScriptsAuthenticateOauth(UserCredential credential)
    {
        try
        {

            ScriptService service = new ScriptService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "MyApp",
            });

           return service;
        }
        catch (Exception ex)
        {
            Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": An authentication error occurred: " + ex.InnerException);
            return null;
        }

    }


    public static UserCredential getCredential(string clientId, string clientSecret, string userName)
    {

        string[] scopes = new string[] { DriveService.Scope.Drive,  // view and manage your files and documents
                                         DriveService.Scope.DriveAppdata,  // view and manage its own configuration data
                                         DriveService.Scope.DriveAppsReadonly,   // view your drive apps
                                         DriveService.Scope.DriveFile,   // view and manage files created by this app
                                         DriveService.Scope.DriveMetadataReadonly,   // view metadata for files
                                         DriveService.Scope.DriveReadonly,   // view files and documents on your drive
                                         DriveService.Scope.DriveScripts, // modify your app scripts
                                         ScriptService.Scope.Drive,

                                         "https://www.googleapis.com/auth/spreadsheets",
                                         "https://spreadsheets.google.com/feeds",
                                         "https://docs.google.com/feeds"};  
        return GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = clientId, ClientSecret = clientSecret }
                                                                                         , scopes
                                                                                         , userName
                                                                                         , CancellationToken.None
                                                                                         , new FileDataStore("Google.Sheet.Sync.Auth.Store")).Result;
    }

    public static DriveService DriveAuthenticateOauth(UserCredential credential)
    {
        try
        {


            DriveService service = new DriveService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "MyApp",
            });

            // Console.WriteLine("Auth success");


            return service;
        }
        catch (Exception ex)
        {

            // Console.WriteLine(ex.InnerException);
            Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": An authentication error occurred: " + ex.InnerException);
            return null;

        }

    }
}

我得到这样的服务:

 var credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
 DriveService driveService = Authentication.DriveAuthenticateOauth(credential);
 ScriptService scriptService = Authentication.ScriptsAuthenticateOauth(credential);

但是大约在一个小时结束时,应用程序脚本调用会引发以下错误:

Script error message: Authorization is required to perform that action.

需要明确的是,它在所有其他时间都有效,只是在接近一小时结束的那 5 分钟内无效。我确实在我的开发人员控制台上以及在应用程序脚本编辑器中的 Resources > Advanced Google services... 下激活了 Google Drive API。

那么发生了什么?这可以解决吗?

4

3 回答 3

2

经过进一步研究,我发现只需要从脚本编辑器运行脚本即可防止出现此错误。这是我找到的信息:

执行该操作需要授权。

此错误表明脚本缺少运行所需的授权。在脚本编辑器中或从自定义菜单项运行脚本时,会向用户显示授权对话框。但是,当脚本作为服务运行、嵌入 Google 协作平台页面或从触发器运行时,无法显示对话框并显示此错误。要授权脚本,请打开脚本编辑器并运行任何函数。为避免此错误,请记住在向脚本添加新服务或功能后在脚本编辑器中运行该脚本一次。

来源:https ://developers.google.com/apps-script/troubleshooting#common_errors

我对代码进行的另一个相关改进是在创建两个服务之前获取凭据对象的新副本:换句话说,我更改了这个:

var credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
DriveService driveService = Authentication.DriveAuthenticateOauth(credential);
ScriptService scriptService = Authentication.ScriptsAuthenticateOauth(credential);

对此:

var credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
DriveService driveService = Authentication.DriveAuthenticateOauth(credential);
credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
ScriptService scriptService = Authentication.ScriptsAuthenticateOauth(credential);

这本身并不能解决我的问题,但它有助于避免 OAuth 怪癖,并且可以防止不必要的令牌刷新。

于 2015-11-16T09:24:14.250 回答
0

如果您的应用程序“就在接近整点的那 5 分钟内”失败,那么您很可能遇到了执行 API 的这个错误

显然,使用将在 6 分钟内过期的令牌对执行 API 的请求会给出“需要授权...”错误。这似乎与 6 分钟是脚本的最长运行时间这一事实有关。

一种解决方法是提前刷新令牌,前提是您知道令牌何时到期(Android 上不是这种情况)。希望该错误将很快得到修复。

我不确定您是否设法真正解决了问题,或者您是否刚刚找到了一个好的解决方法,但您可能希望为该 Apps 脚本问题加注星标,以便尽快解决。

于 2016-10-20T09:21:48.377 回答
0

您可能需要一个刷新令牌。访问令牌通常从 Google 设置为仅使用 3600 秒(1 小时),而刷新令牌的使用时间要长得多,旨在让您在前一个访问令牌过期时轻松获得新的访问令牌。这可能是一个很好的起点:Google API .NET Client information on token response

此外,如果您没有刷新令牌,但您有访问令牌,则可以撤销之前的访问令牌,然后再次进行身份验证。如果正确调用“确保您获得"Bearer"令牌类型”,新响应将具有刷新令牌。

这里有更多关于使用更长寿的刷新令牌的信息

于 2015-11-16T21:21:08.747 回答