2

Я попытался войти в localhost, и все работает правильно.API календаря Google v3 - Запросить время при развертывании на сервере

Код:

public static bool LoginGoogleCalendar(string clientId, string clientSecret, string idGCalendarUser, string calendarServiceScope, string folder) 
    { 
     try 
     { 


      UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
             new ClientSecrets 
             { 
              ClientId = clientId, 
              ClientSecret = clientSecret, 
             }, 
             new[] { calendarServiceScope }, 
             idGCalendarUser, 
             CancellationToken.None, new FileDataStore(folder)).Result; 
      return true; 
     } 
     catch (Exception ex) 
     { 
      Elmah.ErrorSignal.FromCurrentContext().Raise(ex); 
      return false; 
     } 
    } 

(я установил правильно разрешение на fileDataStore)

В Google Developers Console:

Перенаправление URIs: http://localhost/authorize/ Javascript Происхождение: http://localhost:8081

Я использую Visual Studio 2013, IIS 8

Когда я пытаюсь войти на сервер, заблокирует весь сервер за считанные минуты и ответ будет следующий: System.Web.HttpException.

В Google Developers Console:

Перенаправление URIs: http://pippo.pluto.it/authorize/ Javascript Происхождение: http://pippo.pluto.it

На сервере: IIS 7

Ссылка на мой пример: https://developers.google.com/google-apps/calendar/instantiate

+0

Вы можете выполнить ping-сервер с сервера IIS? –

+0

Вы могли бы отправить код для файла fileDataStore, который используете. Код, который вы опубликовали, недостаточен для воссоздания этой проблемы. – DaImTo

+0

Да, ответ сервера на ping. – Tomb86

ответ

2

Я вошел в ту же проблему. Многие примеры в Интернете говорят вам использовать этот класс. Однако для веб-приложений это не тот класс, который нужно использовать. Этот класс работает идеально для «автономных» приложений, но когда вы используете этот класс на сервере IIS, попробуйте открыть всплывающее окно на сервере, но оно не позволит его.

Класс я использую: GoogleAuthorizationCodeFlow

using Google.Apis.Analytics.v3; 
using Google.Apis.Auth.OAuth2; 
using Google.Apis.Auth.OAuth2.Flows; 
using Google.Apis.Auth.OAuth2.Requests; 
using Google.Apis.Auth.OAuth2.Web; 
using Google.Apis.Services; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Web; 

namespace GoogleOauth2DemoWebApp 
{ 
    public class GoogleOauth 
    { 
     public AnalyticsService Handle(string _userId, string _connectionString, string _googleRedirectUri, string _applicationName, string[] _scopes) 
     { 
      try 
      { 
       string UserId = _userId;//The user ID wil be for examlpe the users gmail address. 
       AnalyticsService service; 
       GoogleAuthorizationCodeFlow flow; 
       //use extended class to create google authorization code flow 
       flow = new ForceOfflineGoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer 
       { 
        DataStore = new DbDataStore(_connectionString),//DataStore class to save the token in a SQL database. 
        ClientSecrets = new ClientSecrets { ClientId = "XXX-YOUR CLIENTID-XXX", ClientSecret = "XXX-YOURCLIENTSECRET-XXX" }, 
        Scopes = _scopes, 
       }); 


       var uri = HttpContext.Current.Request.Url.ToString(); 
       string redirecturi = _googleRedirectUri;//This is the redirect URL set in google developer console. 
       var code = HttpContext.Current.Request["code"]; 
       if (code != null) 
       { 
        var token = flow.ExchangeCodeForTokenAsync(UserId, code, 
         uri.Substring(0, uri.IndexOf("?")), CancellationToken.None).Result; 

        var test = HttpContext.Current.Request["state"]; 

        // Extract the right state. 
        var oauthState = AuthWebUtility.ExtracRedirectFromState(
         flow.DataStore, UserId, HttpContext.Current.Request["state"]).Result; 
        HttpContext.Current.Response.Redirect(oauthState); 
       } 
       else 
       { 

        var result = new AuthorizationCodeWebApp(flow, redirecturi, uri).AuthorizeAsync(UserId, 
         CancellationToken.None).Result; 

        if (result.RedirectUri != null) 
        { 
         // Redirect the user to the authorization server. 
         HttpContext.Current.Response.Redirect(result.RedirectUri); 
        } 
        else 
        { 
         // The data store contains the user credential, so the user has been already authenticated. 
         service = new AnalyticsService(new BaseClientService.Initializer() 
         { 
          HttpClientInitializer = result.Credential, 
          ApplicationName = _applicationName 
         }); 
         return service; 
        } 
       } 
       return null; 
      } 
      catch (Exception ex) 
      { 
       throw ex; 
      } 

     } 

     internal class ForceOfflineGoogleAuthorizationCodeFlow : GoogleAuthorizationCodeFlow 
     { 
      public ForceOfflineGoogleAuthorizationCodeFlow(GoogleAuthorizationCodeFlow.Initializer initializer) : base(initializer) { } 

      public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri) 
      { 
       var ss = new Google.Apis.Auth.OAuth2.Requests.GoogleAuthorizationCodeRequestUrl(new Uri(AuthorizationServerUrl)); 
       ss.AccessType = "offline"; 
       ss.ApprovalPrompt = "force"; 
       ss.ClientId = ClientSecrets.ClientId; 
       ss.Scope = string.Join(" ", Scopes); 
       ss.RedirectUri = redirectUri; 
       return ss; 
      } 
     }; 
    } 
} 

Также я пользователь класса DataStore. Сохранение жетонов в файле на вашем сервере не является лучшей практикой. Я использовал базу данных SQL.

Пример класса хранилища данных. Это сделает таблицу для вас, а не лучшим способом, но для тестирования достаточно хорошо.

using Google.Apis.Json; 
using Google.Apis.Util.Store; 
using System; 
using System.Collections.Generic; 
using System.Data.SqlClient; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace GoogleOauth2DemoWebApp 
{ 
    public class DbDataStore : IDataStore 
    { 

     readonly string connectionString; 


     public string ConnectionString { get { return connectionString; } } 
     private Boolean _ConnectionExists { get; set; } 
     public Boolean connectionExists { get { return _ConnectionExists; } } 


     /// <summary> 
     /// Constructs a new file data store with the specified folder. This folder is created (if it doesn't exist 
     /// yet) under the current directory 
     /// </summary> 
     /// <param name="folder">Folder name</param> 
     public DbDataStore(String _connectionString) 
     { 
      connectionString = _connectionString; 

      SqlConnection myConnection = this.connectdb(); // Opens a connection to the database. 

      if (_ConnectionExists) 
      { 
       // check if the Table Exists; 
       try 
       { 
        SqlDataReader myReader = null; 
        SqlCommand myCommand = new SqlCommand("select 1 from GoogleUser where 1 = 0", 
              myConnection); 
        myReader = myCommand.ExecuteReader(); 
        while (myReader.Read()) 
        { 
         var hold = myReader["Column1"]; 
        } 
       } 
       catch 
       { 
        // table doesn't exist we create it 
        SqlCommand myCommand = new SqlCommand("CREATE TABLE [dbo].[GoogleUser](" + 
                  " [username] [nvarchar](4000) NOT NULL," + 
                  " [RefreshToken] [nvarchar](4000) NOT NULL," + 
                  " [Userid] [nvarchar](4000) NOT NULL" + 
                  ") ON [PRIMARY]", myConnection); 
        myCommand.ExecuteNonQuery(); 
       } 
      } 

      myConnection.Close(); 
     } 

     /// <summary> 
     /// Stores the given value for the given key. It creates a new file (named <see cref="GenerateStoredKey"/>) in 
     /// <see cref="FolderPath"/>. 
     /// </summary> 
     /// <typeparam name="T">The type to store in the data store</typeparam> 
     /// <param name="key">The key</param> 
     /// <param name="value">The value to store in the data store</param> 
     public Task StoreAsync<T>(string key, T value) 
     { 

      if (string.IsNullOrEmpty(key)) 
      { 
       throw new ArgumentException("Key MUST have a value"); 
      } 
      var serialized = NewtonsoftJsonSerializer.Instance.Serialize(value); 

      SqlConnection myConnection = this.connectdb(); 
      if (!_ConnectionExists) 
      { 
       throw new Exception("Not connected to the database"); 
      } 

      // Try and find the Row in the DB. 
      using (SqlCommand command = new SqlCommand("select Userid from GoogleUser where UserName = @username", myConnection)) 
      { 
       command.Parameters.AddWithValue("@username", key); 

       string hold = null; 
       SqlDataReader myReader = command.ExecuteReader(); 
       while (myReader.Read()) 
       { 
        hold = myReader["Userid"].ToString(); 
       } 
       myReader.Close(); 


       if (hold == null) 
       { 
        try 
        { 
         // New User we insert it into the database 
         string insertString = "INSERT INTO [dbo].[GoogleUser] ([username],[RefreshToken],[Userid]) " + 
               " VALUES (@key,@value,'1')"; 

         SqlCommand commandins = new SqlCommand(insertString, myConnection); 
         commandins.Parameters.AddWithValue("@key", key); 
         commandins.Parameters.AddWithValue("@value", serialized); 
         commandins.ExecuteNonQuery(); 
        } 
        catch (Exception ex) 
        { 

         throw new Exception("Error inserting new row: " + ex.Message); 

        } 


       } 
       else 
       { 
        try 
        { 
         // Existing User We update it       
         string insertString = "update [dbo].[GoogleUser] " + 
               " set [RefreshToken] = @value " + 
               " where username = @key"; 

         SqlCommand commandins = new SqlCommand(insertString, myConnection); 
         commandins.Parameters.AddWithValue("@key", key); 
         commandins.Parameters.AddWithValue("@value", serialized); 
         commandins.ExecuteNonQuery(); 
        } 
        catch (Exception ex) 
        { 

         throw new Exception("Error updating user: " + ex.Message); 

        } 
       } 
      } 


      myConnection.Close(); 
      return TaskEx.Delay(0); 
     } 

     /// <summary> 
     /// Deletes the given key. It deletes the <see cref="GenerateStoredKey"/> named file in <see cref="FolderPath"/>. 
     /// </summary> 
     /// <param name="key">The key to delete from the data store</param> 
     public Task DeleteAsync<T>(string key) 
     { 

      if (string.IsNullOrEmpty(key)) 
      { 
       throw new ArgumentException("Key MUST have a value"); 
      } 
      SqlConnection myConnection = this.connectdb(); 
      if (!_ConnectionExists) 
      { 
       throw new Exception("Not connected to the database"); 
      } 

      // Deletes the users data.       
      string deleteString = "delete from [dbo].[GoogleUser] " + 
            "where username = @key"; 
      SqlCommand commandins = new SqlCommand(deleteString, myConnection); 
      commandins.Parameters.AddWithValue("@key", key); 
      commandins.ExecuteNonQuery(); 


      myConnection.Close(); 
      return TaskEx.Delay(0); 
     } 

     /// <summary> 
     /// Returns the stored value for the given key or <c>null</c> if the matching file (<see cref="GenerateStoredKey"/> 
     /// in <see cref="FolderPath"/> doesn't exist. 
     /// </summary> 
     /// <typeparam name="T">The type to retrieve</typeparam> 
     /// <param name="key">The key to retrieve from the data store</param> 
     /// <returns>The stored object</returns> 
     public Task<T> GetAsync<T>(string key) 
     { 
      //Key is the user string sent with AuthorizeAsync 
      if (string.IsNullOrEmpty(key)) 
      { 
       throw new ArgumentException("Key MUST have a value"); 
      } 
      TaskCompletionSource<T> tcs = new TaskCompletionSource<T>(); 


      // Note: create a method for opening the connection. 
      SqlConnection myConnection = new SqlConnection(this.ConnectionString); 
      myConnection.Open(); 

      // Try and find the Row in the DB. 
      using (SqlCommand command = new SqlCommand("select RefreshToken from GoogleUser where UserName = @username;", myConnection)) 
      { 
       command.Parameters.AddWithValue("@username", key); 

       string RefreshToken = null; 
       SqlDataReader myReader = command.ExecuteReader(); 
       while (myReader.Read()) 
       { 
        RefreshToken = myReader["RefreshToken"].ToString(); 
       } 

       if (RefreshToken == null) 
       { 
        // we don't have a record so we request it of the user. 
        tcs.SetResult(default(T)); 
       } 
       else 
       { 

        try 
        { 
         // we have it we use that. 
         tcs.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize<T>(RefreshToken)); 
        } 
        catch (Exception ex) 
        { 
         tcs.SetException(ex); 
        } 

       } 
      } 

      return tcs.Task; 
     } 

     /// <summary> 
     /// Clears all values in the data store. This method deletes all files in <see cref="FolderPath"/>. 
     /// </summary> 
     public Task ClearAsync() 
     { 

      SqlConnection myConnection = this.connectdb(); 
      if (!_ConnectionExists) 
      { 
       throw new Exception("Not connected to the database"); 
      } 

      // Removes all data from the Table. 
      string truncateString = "truncate table [dbo].[GoogleUser] "; 
      SqlCommand commandins = new SqlCommand(truncateString, myConnection); 
      commandins.ExecuteNonQuery(); 

      myConnection.Close(); 
      return TaskEx.Delay(0); 
     } 

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



     //Handel's creating the connection to the database 
     private SqlConnection connectdb() 
     { 

      SqlConnection myConnection = null; 
      try 
      { 
       myConnection = new SqlConnection(this.ConnectionString); 
       try 
       { 
        myConnection.Open(); 
        // ensuring that we are able to make a connection to the database. 
        if (myConnection.State == System.Data.ConnectionState.Open) 
        { 
         _ConnectionExists = true; 
        } 
        else 
        { 
         throw new ArgumentException("Error unable to open connection to the database."); 
        } 
       } 
       catch (Exception ex) 
       { 

        throw new ArgumentException("Error opening Connection to the database: " + ex.Message); 
       } 

      } 
      catch (Exception ex) 
      { 

       throw new ArgumentException("Error creating Database Connection: " + ex.Message); 
      } 

      return myConnection; 
     } 
    } 
} 

используя класс:

GoogleOauth g = new GoogleOauth(); 
       AnalyticsService service = g.Handle(userEmailAddress, 
        connectionString, redirectUrl, 
        "YOURAPLICATIONNAME", 
        new[] {AnalyticsService.Scope.AnalyticsReadonly}); 

       DataResource.RealtimeResource.GetRequest request = service.Data.Realtime.Get(String.Format("ga:{0}", profileId), "rt:activeUsers"); 
       RealtimeData feed = request.Execute(); 

Если люди заинтересуют я могу загрузить пример проекта на GitHub.

+0

У меня тоже есть улучшенный токен хранения в базе данных, но это не решило проблему выше. Вот ссылка: http://www.daimto.com/google-calendar-api-authentication-with-c/#Google_CalendarAPI_Service_Account_Authentication Здесь класс для хранения: https://github.com/LindaLawton /Google-Dotnet-Samples/blob/master/Authentication/Diamto.Google.Authentication/Diamto.Google.Authentication/DatabaseDataStore.cs – Tomb86

+0

С некоторыми изменениями в коде я смог достичь ожидаемых результатов. Спасибо. Что мне нужно было сделать, так это определить, требуется ли АВТОРИЗАЦИЯ или нет, потому что это предназначалось для запуска в виде безголового фонового процесса, поэтому, если требуется AUTH, никто не сможет его исправить. Будет отправлено уведомление, и правильный пользователь сможет выполнить процесс AUTH. –