【问题标题】:Viewing Google Calendar in Winfroms Browser Control在 Winforms 浏览器控件中查看 Google 日历
【发布时间】:2021-10-07 16:18:43
【问题描述】:

我想在 winforms 的网络浏览器控件中显示我的 Google 日历。

我尝试按照教程https://www.daimto.com/google-api-and-oath2/

但不幸的是,我仍然没有获得访问我的谷歌日历的权限,“浏览器不安全......”。

我知道我必须以某种方式使用这些权限,但我不知道如何。

代码:

 public partial class Kalender : UserControl
{
    public string clientId = "897492813624-glvfpm6heik1fqr7s2mjtl6eme5ad8bq.apps.googleusercontent.com";
    public string redirectUri = "https://calendar.google.com/";
    public string clientSecret = "HYGFBEd_BZPcWcrPopsX4uZr";
    public string redirectURI = "https://calendar.google.com/";
    public AuthResponse access;

    public Kalender()
    {
        InitializeComponent();
        webKalender.Navigate(AuthResponse.GetAutenticationURI(clientId, redirectUri));
    }

    private void webKalender_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        
        string Mytitle = ((WebBrowser)sender).DocumentTitle.ToLower();
        if (Mytitle.IndexOf("success code=") > -1)
        {
            webKalender.Visible = false;

            // searching the body for our code
            string AuthCode = webKalender.DocumentTitle.Replace("Success code=", "");
            string webText = ((WebBrowser)sender).DocumentText;
            int start = webText.IndexOf("id=\"code\"");
            start = webText.IndexOf(AuthCode, start);
            int end = webText.IndexOf('"', start);
            string authCode = webText.Substring(start, end - start);

            //Exchange the code for Access token and refreshtoken.
            access = AuthResponse.Exchange(authCode, clientId, clientSecret, redirectURI);

            //processAccess();
        }
    }

教程中的课程:

 public class AuthResponse
    {
        private string access_token;
        public string Access_token
        {
            get
            {
                // Access token lasts an hour if its expired we get a new one.
                if (DateTime.Now.Subtract(created).Hours > 1)
                {
                    refresh();
                }
                return access_token;
            }
            set { access_token = value; }
        }
        public string refresh_token { get; set; }
        public string clientId { get; set; }
        public string secret { get; set; }
        public string expires_in { get; set; }
        public DateTime created { get; set; }


       

         //"{\n  \"access_token\" : \"ya29.kwFUj-la2lATSkrqFlJXBqQjCIZiTg51GYpKt8Me8AJO5JWf0Sx6-0ZWmTpxJjrBrxNS_JzVw969LA\",\n  \"token_type\" : \"Bearer\",\n  \"expires_in\" : 3600,\n  \"refresh_token\" : \"1/ejoPJIyBAhPHRXQ7pHLxJX2VfDBRz29hqS_i5DuC1cQ\"\n}"
      

        public static AuthResponse get(string response)
        {
            AuthResponse result = (AuthResponse)JsonConvert.DeserializeObject(response);
            result.created = DateTime.Now;   // DateTime.Now.Add(new TimeSpan(-2, 0, 0)); //For testing force refresh.
            return result;
        }


        public void refresh()
        {
            var request = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
            string postData = string.Format("client_id={0}&client_secret={1}&refresh_token={2}&grant_type=refresh_token", this.clientId, this.secret, this.refresh_token);
            var data = Encoding.ASCII.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();
            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
            var refreshResponse = AuthResponse.get(responseString);
            this.access_token = refreshResponse.access_token;
            this.created = DateTime.Now;
        }


        public static AuthResponse Exchange(string authCode, string clientid, string secret, string redirectURI)
        {

            var request = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");

            string postData = string.Format("code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code", authCode, clientid, secret, redirectURI);
            var data = Encoding.ASCII.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();

            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

            var x = AuthResponse.get(responseString);

            x.clientId = clientid;
            x.secret = secret;

            return x;

        }



        public static Uri GetAutenticationURI(string clientId, string redirectUri)
        {
            string scopes = "https://www.googleapis.com/auth/calendar";

            if (string.IsNullOrEmpty(redirectUri))
            {
                redirectUri = "urn:ietf:wg:oauth:2.0:oob";
            }
            string oauth = string.Format("https://accounts.google.com/o/oauth2/auth?client_id={0}&redirect_uri={1}&scope={2}&response_type=code", clientId, redirectUri, scopes);
            return new Uri(oauth);
        }

    }

对德国人感到抱歉,但它说的是:“浏览器或应用程序我不安全。使用不同的浏览器。”

【问题讨论】:

  • 请编辑您的问题并附上您的授权码,如果没有看到您尝试过的内容,我们将无法帮助您解决哪些问题。此外,calendar.google.com 不是对 Google 日历 api 的 api 调用的正确格式。您了解 google 日历 api 是否会以 Json 格式返回数据取决于您。
  • 这是您遇到的错误吗? developers.googleblog.com/2021/06/…您使用的是哪个版本的 .net 框架?
  • 我添加了两张网页浏览器中正在发生的事情的图片。我在 .net 框架 4.8
  • 本机默认安装的是哪个浏览器?好的,在我尝试调试这个之前,您不想使用 google .net 客户端库的任何原因?您应该可以将其与已安装的应用程序一起使用,这没有问题。我最初编写该教程是因为我使用的是库不支持的 .net 3.5。

标签: c# winforms oauth google-oauth google-calendar-api


【解决方案1】:

我想在 winforms 的网络浏览器控件中显示我的 Google 日历。

您应该了解的第一件事是,如果您尝试在您的应用程序中显示 Google 日历 Web 应用程序,那么如果不使用该代码或任何代码,它就无法工作。

您可以使用 Google 日历 API 访问 Google 日历数据,然后在您的网络表单中创建您自己的数据显示。

这就是您使用的代码的设计目的。但是它已经九岁多了。

如果可能,您应该使用 Google .net 客户端库。话虽如此,您使用的代码最初是为 .Net 3.5 九年前编写的。 google .net 客户端库不支持 .net 3.5。 (我指的不是我们所说的更老的 .Net core 3.1。)

从那时起,安全性发生了很多变化。如果 Google 检测到您正在 web 视图中打开它,那么它可能无法正常工作。如今,验证屏幕的唯一工作方式是在机器上安装的浏览器中打开 oauth 窗口。

.net 客户端库就是为此而设计的。

这里有一些授权代码可以帮助您入门。

public static class Oauth2Example
    {
        /// <summary>
        /// ** Installed Aplication only ** 
        /// This method requests Authentcation from a user using Oauth2.  
        /// </summary>
        /// <param name="clientSecretJson">Path to the client secret json file from Google Developers console.</param>
        /// <param name="userName">Identifying string for the user who is being authentcated.</param>
        /// <param name="scopes">Array of Google scopes</param>
        /// <returns>CalendarService used to make requests against the Calendar API</returns>
        public static CalendarService GetCalendarService(string clientSecretJson, string userName, string[] scopes)
        {
            try
            {
                if (string.IsNullOrEmpty(userName))
                    throw new ArgumentNullException("userName");
                if (string.IsNullOrEmpty(clientSecretJson))
                    throw new ArgumentNullException("clientSecretJson");
                if (!File.Exists(clientSecretJson))
                    throw new Exception("clientSecretJson file does not exist.");

                var cred = GetUserCredential(clientSecretJson, userName, scopes);
                return GetService(cred);

            }
            catch (Exception ex)
            {
                throw new Exception("Get Calendar service failed.", ex);
            }
        }

        /// <summary>
        /// ** Installed Aplication only ** 
        /// This method requests Authentcation from a user using Oauth2.  
        /// Credentials are stored in System.Environment.SpecialFolder.Personal
        /// Documentation https://developers.google.com/accounts/docs/OAuth2
        /// </summary>
        /// <param name="clientSecretJson">Path to the client secret json file from Google Developers console.</param>
        /// <param name="userName">Identifying string for the user who is being authentcated.</param>
        /// <param name="scopes">Array of Google scopes</param>
        /// <returns>authencated UserCredential</returns>
        private static UserCredential GetUserCredential(string clientSecretJson, string userName, string[] scopes)
        {
            try
            {
                if (string.IsNullOrEmpty(userName))
                    throw new ArgumentNullException("userName");
                if (string.IsNullOrEmpty(clientSecretJson))
                    throw new ArgumentNullException("clientSecretJson");
                if (!File.Exists(clientSecretJson))
                    throw new Exception("clientSecretJson file does not exist.");

                // These are the scopes of permissions you need. It is best to request only what you need and not all of them               
                using (var stream = new FileStream(clientSecretJson, FileMode.Open, FileAccess.Read))
                {
                    string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
                    credPath = Path.Combine(credPath, ".credentials/", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);

                    // Requesting Authentication or loading previously stored authentication for userName
                    var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
                                                                             scopes,
                                                                             userName,
                                                                             CancellationToken.None,
                                                                             new FileDataStore(credPath, true)).Result;

                    credential.GetAccessTokenForRequestAsync();
                    return credential;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Get user credentials failed.", ex);
            }
        }

        /// <summary>
        /// This method get a valid service
        /// </summary>
        /// <param name="credential">Authecated user credentail</param>
        /// <returns>CalendarService used to make requests against the Calendar API</returns>
        private static CalendarService GetService(UserCredential credential)
        {
            try
            {
                if (credential == null)
                    throw new ArgumentNullException("credential");

                // Create Calendar API service.
                return new CalendarService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Calendar Oauth2 Authentication Sample"
                });
            }
            catch (Exception ex)
            {
                throw new Exception("Get Calendar service failed.", ex);
            }
        }
    }

【讨论】:

  • 感谢您的帮助。你能给我一个链接,我可以在那里获取客户端库吗?
  • 谢谢,所以我的应用程序中没有直接使用谷歌日历的正确方法吗?
  • 确保使用该代码,您的应用程序将授权用户,并且您将能够访问谷歌日历 API。 samplesnewer tutoiral
  • 我知道我可以从我的谷歌日历中获取事件等,但我想在 webbrowser 控件中打开它以便像在普通 chrome 浏览器中一样使用它。
猜你喜欢
  • 2013-08-24
  • 2013-09-16
  • 1970-01-01
  • 2011-06-17
  • 2018-02-19
  • 1970-01-01
  • 2011-05-04
  • 2012-04-10
  • 2011-09-07
相关资源
最近更新 更多