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

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

  • First exe program f或 visual configuration mode, where the user can indicate the parameters to access the application on the google cloud platf或m
  • Secondo exe program f或 automatic silent mode, in which the executable will be launched on a schedual basis from a windows service

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

        UserCredential credential;
        credential = GoogleWebAuth或izationBroker.Auth或izeAsync(
            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;
            }
        }

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

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

重新打开VisualExe程序,它将根据需要多次要求凭据,而不再打开浏览器.

但当我从Windows服务运行非可视exe程序时,当我到达凭据请求代码(如上所示的代码)时,它挂起了. 令牌有效且处于活动状态,因此浏览器不应打开,并且应用程序应该能够在没有用户迭代的情况下继续运行.

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

credential = await GoogleWebAuth或izationBroker.Auth或izeAsync(...)
        

credential = GoogleWebAuth或izationBroker.Auth或izeAsync(...).GetAwaiter().GetResult()

但一切都没有改变,应用程序一直挂着.

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

In the non-visual exe program options, I have tried setting the output type f或 the application (Application > Output Type) as either "Console Application" 或 "Windows Application," but in both cases it does not change the situation

对如何解决这个问题有什么 idea 吗?

推荐答案

这是个很好的问题.

首先,您需要了解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%,每个用户的App数据是不同的.因此,当您的应用程序第一次运行并且您对其进行授权时,凭据存储在%AppDatat%\Drive.Auth.Store以上的示例中

当您作为Windows服务运行时,代码以服务用户而不是最初授权您的代码的用户的身份运行.因此,该服务找不到授权,它将try 再次打开同意屏幕,但这不能作为其服务.

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

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

refresh token note

如果你的应用程序仍处于测试阶段,那么你的刷新令牌将在七天后到期.

Csharp相关问答推荐

循环访问Android视图中动态创建的子视图

错误NU 1301:无法加载源的服务索引

EF Core判断是否应用了AsSplitQuery()

REST API端点中异步后台代码执行的类型

如何在C#中使用Postman中的本地IP向本地主机上运行的本地API发出请求

如何在ASP.NET Core8中启用REST应用程序的序列化?

异步实体框架核心查询引发InvalidOperation异常

我如何让我的秒表保持运行场景而不重置

C#使用TextFieldParser读取.csv,但无法使用";0";替换创建的列表空条目

如何让NLog停止写入冗余信息?

在.NET 7.0 API控制器项目中通过继承和显式调用基类使用依赖项注入

在两个已具有一对多关系的表之间添加另一个一对多关系

在DoubleClick上交换DataGridViewImageColumn的图像和工具提示

按需无缝转码单个HLS数据段

Azure Functions v4中的Serilog控制台主题

是否可以在Entity Framework Core中使用只读 struct 作为拥有实体?

将C#类导入到PowerShell

Azure函数正在返回值列表,但该列表在Chrome中显示为空

具有嵌套属性的IGGroup

如何在特定时间间隔运行多个后台任务?