【问题标题】:Google Calendar API Authentication .NET browser windowGoogle 日历 API 身份验证 .NET 浏览器窗口
【发布时间】:2014-07-03 09:14:03
【问题描述】:

我正在使用最新版本的 Google .NET Client API (v1.81)。我正在尝试使用以下代码连接到日历服务

    var calendarService = new CalendarService(new BaseClientService.Initializer
    {
        HttpClientInitializer = GetCredential(),
        ApplicationName = "MyApp"
    });

    public UserCredential GetCredential()
    {
        UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
            new ClientSecrets { ClientId = _clientId, ClientSecret = _clientSecret },
            new[] { CalendarService.Scope.Calendar }.ToList(), "user", CancellationToken.None,
            new FileDataStore("Drive.Auth.Store")).Result;

        return credential;
    }

当我这样做时,它会打开一个新的浏览器窗口并要求我进行身份验证。我之前已经过身份验证,并且通过 FileDataStore 存储和检索密钥。

为什么会要求我再次进行身份验证?问题是因为此代码需要在后台服务中运行,因此无法打开浏览器选项卡。

我现在遇到的另一个问题是,当我尝试授权它会打开一个新的浏览器窗口时,我选择了我的凭据,但登录页面会告诉我

“请求中的重定向 URI:http://localhost:51773/authorize/ 与注册的重定向 URI 不匹配”

为什么它尝试使用授权 url 而不是 AuthCallbackController。它似乎还随机更改了重定向 uri 的端口号,使其无法注册。

最终的问题可能是,如果我有一个 Web 应用程序,并且我希望用户通过网页使用他们的凭据登录,然后稍后在服务器上的后台任务中重用这些凭据,我该怎么做去吧?我找不到任何相关的示例应用程序来展示如何。 FileDataStore 似乎不存储凭据,因此可以重复使用它们。我还实现了我自己的 DataStore,它将它们保存在似乎也不起作用的数据库中。

进一步深入研究,看来我需要offline_access。我已经实现了与Google Analytics OAuth with AccessType = Offline in C# 相同的功能,但它仍然会提示。如何重复使用 offline_access 刷新令牌?

【问题讨论】:

  • 每次调用 GetCredential 时都会发生这种情况吗?您确定凭据已保存在数据存储中吗?你能检查文件是否存在于资源管理器中吗?
  • 是的,我确定它已经保存了。
  • "请求中的重定向 URI:localhost:51773/authorize 与注册的重定向 URI 不匹配" - 如果您使用 Web 应用程序,请查看:developers.google.com/api-client-library/dotnet/guide/…,您是否将重定向 URI 设置为开发人员控制台上的 your_site/AuthCallback/IndexAsync。如果没有,您需要在开发者控制台上创建一个原生应用程序(而不是 Web 应用程序)。
  • 我将检查开发人员控制台以确保已设置。我确实在演示中尝试了控制台应用程序,但它们仍然打开了一个网络浏览器。如果应用程序作为后台任务(无 UI)运行,这将不是一件好事。

标签: c# google-calendar-api google-api-dotnet-client


【解决方案1】:

您是正确的,您需要创建自己的 Idatastore 的 imp 实现。这将允许您将刷新令牌保存到数据库并稍后使用。

这是一个非常粗略的例子

/// 
 /// Saved data store that implements . 
 /// This Saved data store stores a StoredResponse object.
 /// 
    class SavedDataStore : IDataStore
    {
        public StoredResponse _storedResponse { get; set; }
        /// 
        /// Constructs Load previously saved StoredResponse.
        /// 
        ///Stored response
        public SavedDataStore(StoredResponse pResponse)
        {
            this._storedResponse = pResponse;
        }
        public SavedDataStore()
        {
            this._storedResponse = new StoredResponse();
        }
        /// 
        /// Stores the given value. into storedResponse
        /// .
        /// 
        ///The type to store in the data store
        ///The key
        ///The value to store in the data store
        public Task StoreAsync(string key, T value)
        {
            var serialized = NewtonsoftJsonSerializer.Instance.Serialize(value);
            JObject jObject = JObject.Parse(serialized);
            // storing access token
            var test = jObject.SelectToken("access_token");
            if (test != null)
            {
                this._storedResponse.access_token = (string)test;
            }
            // storing token type
            test = jObject.SelectToken("token_type");
            if (test != null)
            {
                this._storedResponse.token_type = (string)test;
            }
            test = jObject.SelectToken("expires_in");
            if (test != null)
            {
                this._storedResponse.expires_in = (long?)test;
            }
            test = jObject.SelectToken("refresh_token");
            if (test != null)
            {
                this._storedResponse.refresh_token = (string)test;
            }
            test = jObject.SelectToken("Issued");
            if (test != null)
            {
                this._storedResponse.Issued = (string)test;
            }
            return TaskEx.Delay(0);
        }

        /// 
        /// Deletes StoredResponse.
        /// 
        ///The key to delete from the data store
        public Task DeleteAsync(string key)
        {
            this._storedResponse = new StoredResponse();
            return TaskEx.Delay(0);
        }

        /// 
        /// Returns the stored value for_storedResponse      
        ///The type to retrieve
        ///The key to retrieve from the data store
        /// The stored object
        public Task GetAsync(string key)
        {
            TaskCompletionSource tcs = new TaskCompletionSource();
            try
            {
                string JsonData = Newtonsoft.Json.JsonConvert.SerializeObject(this._storedResponse);
                tcs.SetResult(Google.Apis.Json.NewtonsoftJsonSerializer.Instance.Deserialize(JsonData));
            }
            catch (Exception ex)
            {
                tcs.SetException(ex);
            }
            return tcs.Task;
        }

        /// 
        /// Clears all values in the data store. 
        /// 
        public Task ClearAsync()
        {
            this._storedResponse = new StoredResponse();
            return TaskEx.Delay(0);
        }

        ///// Creates a unique stored key based on the key and the class type.
        /////The object key
        /////The type to store or retrieve
        //public static string GenerateStoredKey(string key, Type t)
        //{
        //    return string.Format("{0}-{1}", t.FullName, key);
        //}
    }

现在您将调用 savedDataStore 而不是调用 filedatastore

 //Now we load our saved refreshToken. Probably from the DB someplace but this works
  StoredResponse myStoredResponse = new StoredResponse(tbRefreshToken.Text);
 // Now we pass a SavedDatastore with our StoredResponse.

credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
             new ClientSecrets { ClientId = "YourClientId", ClientSecret = "YourClientSecret" },
              new[] { DriveService.Scope.Drive,
                DriveService.Scope.DriveFile },
              "user",
              CancellationToken.None,
               new SavedDataStore(myStoredResponse)).Result; }

我有一个教程和示例项目。目前适用于 Google Drive 范围,您可以轻松更改这些范围,示例项目位于底部。 Google Oauth2 C#

【讨论】:

  • @DalmTo 我使用 c# 创建了 windows 服务来将事件同步到 Google 日历。在创建 windows 服务之前,我创建了 windows 窗体应用程序并执行。它运作良好。通过windows服务,它不起作用。我发布了问题stackoverflow.com/questions/30936438/…
猜你喜欢
  • 2021-09-29
  • 2016-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
相关资源
最近更新 更多