用于 OAuth2 连接到 GMail 的 C# GoogleWebAuthorizationBroker 在 Windows 服务中不起作用

问题描述 投票:0回答:3

我的应用程序是使用 .NET Framework 4.7.2 编写的。 我创建的应用程序必须与 GMail 邮箱交互才能下载邮件(通过 POP3)。为了通过 OAuth2 对邮箱的应用程序进行身份验证,我在 Google Cloud Platform 上创建了一个应用程序,并从该应用程序中通过 IdClient 和 IdSecret 进行身份验证。

我的应用程序由两个可执行程序组成:

  • 第一个可视化配置模式的exe程序,用户可以在其中指定参数来访问谷歌云平台上的应用程序
  • 用于自动静默模式的第二个 exe 程序,其中可执行文件将从 Windows 服务定期启动

为了对云平台上创建的应用程序进行身份验证,我使用 Google.Apis.Auth NuGet 包。 为了请求令牌,我使用以下代码。此代码由我的应用程序中的两个可执行程序共享

        UserCredential credential;
        credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
            new ClientSecrets
            {
                ClientId = "XXXXXXX",
                ClientSecret = "XXXXXXX"
            },
            new[] { "https://mail.google.com/" },
            "user",
            System.Threading.CancellationToken.None).Result;

        if (credential.Token.IsExpired(credential.Flow.Clock))
        {
            if (!(credential.RefreshTokenAsync(CancellationToken.None).Result))
            {
                CrmEMFunc.LogMessage("Access token can't be refreshed");
                return;
            }
        }

在首次安装期间,配置应用程序(可视化应用程序)将运行,以便用户可以输入身份验证所需的所有参数。 第一次保存连接配置时,将打开浏览器以请求同意通过在云平台上创建的应用程序访问电子邮件。

此配置阶段成功完成后,将生成一个令牌,只要不被撤销,就可以使用或刷新该令牌。因此,对于未来的所有执行,将不再需要查看浏览器来请求同意。

重新打开可视化 exe 程序,它会根据需要多次要求凭据,而无需再打开浏览器。

但是当我从 Windows 服务运行非可视 exe 程序时,当我到达凭据请求代码(上面显示的代码)时,它挂起。 令牌有效且处于活动状态,因此浏览器不应打开,并且应用程序应该能够继续运行而无需用户迭代。

我还尝试使用 await 或方法 GetAwaiter().GetResult() 方法

credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(...)
        

credential = GoogleWebAuthorizationBroker.AuthorizeAsync(...).GetAwaiter().GetResult()

但是什么都没有改变,应用程序一直挂起。

在Windows服务上,我激活了选项“允许服务与桌面交互”(服务>属性>连接>本地系统帐户),但问题仍然出现。

在非可视exe程序选项中,我尝试将应用程序的输出类型(应用程序>输出类型)设置为“控制台应用程序”或“Windows应用程序”,但在这两种情况下都不会改变情况

关于如何解决这个问题有什么想法吗?

c# oauth google-oauth gmail-api google-api-dotnet-client
3个回答
2
投票

这是一个很好的问题。

首先您需要了解 GoogleWebAuthorizationBroker 如何存储用户凭据。

让我们看看比您拥有的更高级的版本。

credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
      GoogleClientSecrets.Load(stream).Secrets,
      new[] { DriveService.Scope.Drive,  DriveService.Scope.DriveFile },
      "LookIAmAUniqueUser",
       CancellationToken.None,
      new FileDataStore("Drive.Auth.Store")                               
      ).Result;

默认情况下,FileDataStore 存储用户授权凭据 %AppData% 每个用户的应用程序数据都不同。因此,当您的应用程序第一次运行并且您授权它时,凭据将存储在上面的示例中

%AppDatat%\Drive.Auth.Store

当您作为 Windows 服务运行时,代码将作为服务用户运行,而不是最初授权您的代码的用户。因此,服务无法找到授权,它将尝试再次打开同意屏幕,但它无法作为服务。

解决方案是为 FileDataStore 提供 Windows 服务可以访问的目录。然后再次授权,将使用凭据创建文件,然后当服务运行时它将具有访问权限。

new FileDataStore(@"c:\datastore",true)   

刷新令牌备注

如果您的应用程序仍处于测试阶段,那么您的刷新令牌将在 7 天后过期。


0
投票

https://console.cloud.google.com/ 上检查您的设置,并使用正确的 URI“xx/signin-google


0
投票

我按照你说的更多指示进行操作,但是当我到达我的线路时

credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.FromStream(stream).Secrets,
                                                                     new[] { DriveService.Scope.Drive, DriveService.Scope.DriveFile },
                                                                     "user",
                                                                     CancellationToken.None,
                                                                     new FileDataStore("Drive.Auth.Store")).Result;

我遇到一个错误,因为他尝试打开浏览器。你知道为什么吗?

© www.soinside.com 2019 - 2024. All rights reserved.