I'm building an MVC app that will authenticate users on our website that want us to post events into their calendars. I've installed the .NET C# client library as well as the Auth and MVC packages.
Using Google.Apis.Auth.OAuth2.Mvc I'm having trouble accessing the TokenResponse
in my implementation of IDataStore
, instead it saves the URL as the token i.e. localhost:6055/calendar/calendarasync/deantest04556734
All of the examples that I've found seem to be out of date, not using the Mvc package and not implementing a DataStore to save to a database so I've usedUsing bits of code from daimto's example and the official examples to get started.
Can anyone point me in the right direction or see any issues with my code?
DatabaseDataStore
public class DatabaseDataStore : IDataStore
{
private SqlConnection connection;
public DatabaseDataStore(SqlConnection sqlConn)
{
if (sqlConn != null)
{
connection = sqlConn;
if(connection.State != ConnectionState.Open)
connection.Open();
}
}
/// <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);
string userId = getUserId(key);
if (userId == null)
{
insertUserData(key, serialized);
}
else
{
updateUserData(userId, key, serialized);
}
return Task.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>();
string refreshToken = null;
// Try and find the Row in the DB.
using (SqlCommand cmd = new SqlCommand("Calendar_GetRefreshToken", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 2700;
try
{
cmd.Parameters.AddWithValue("@username", key);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
refreshToken = reader["RefreshToken"].ToString();
}
reader.Dispose();
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);
}
}
}
catch (Exception ex)
{
//logger.Error("Method:CheckLocalProperty - id: " + propId + " - Error:" + ex.Message);
return null;
}
}
return tcs.Task;
}
/// <summary>
/// Clears all values in the data store. This method deletes all files in <see cref="FolderPath"/>.
/// </summary>
public Task ClearAsync()
{
// Removes all data from the Table.
string truncateString = "truncate table [dbo].[tblCactusGoogleUsers] ";
SqlCommand commandins = new SqlCommand(truncateString, connection);
commandins.ExecuteNonQuery();
return Task.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");
}
deleteUserData(key);
return Task.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);
}
private string getUserId(string value)
{
using (SqlCommand cmd = new SqlCommand("Calendar_GetUserId", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 2700;
try
{
cmd.Parameters.AddWithValue("@username", value);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
return reader["UserId"].ToString();
}
reader.Dispose();
}
catch (Exception ex)
{
//logger.Error("Method:CheckLocalProperty - id: " + propId + " - Error:" + ex.Message);
return null;
}
}
return null;
}
private void insertUserData(string key, string value)
{
using (SqlCommand cmd = new SqlCommand("Calendar_InsertUser", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 2700;
try
{
cmd.Parameters.AddWithValue("@token", value);
cmd.Parameters.AddWithValue("@username", key);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
//logger.Error("Method:insertUserData - id: " + key + " - Error:" + ex.Message);
}
}
}
private void updateUserData(string userId, string key, string value)
{
using (SqlCommand cmd = new SqlCommand("Calendar_UpdateUser", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 2700;
try
{
cmd.Parameters.AddWithValue("@userid", userId);
cmd.Parameters.AddWithValue("@username", key);
cmd.Parameters.AddWithValue("@token", value);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
//logger.Error("Method:updateUserData - id: " + key + " - Error:" + ex.Message);
}
}
}
private void deleteUserData(string key)
{
using (SqlCommand cmd = new SqlCommand("Calendar_DeleteUser", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 2700;
try
{
cmd.Parameters.AddWithValue("@username", key);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
//logger.Error("Method:deleteUserData - id: " + key + " - Error:" + ex.Message);
}
}
}
}
FlowMetadata
public class AppAuthFlowMetadata : FlowMetadata
{
private SqlConnection connection;
private readonly IAuthorizationCodeFlow flow;
public AppAuthFlowMetadata(SqlConnection sqlConn, string clientId, string clientSecret)
{
if (sqlConn != null)
{
connection = sqlConn;
if (connection.State != ConnectionState.Open)
connection.Open();
flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientSecret
},
Scopes = new[] {
CalendarService.Scope.Calendar
},
DataStore = new DatabaseDataStore(connection)
});
}
else
{
throw new ArgumentException("sqlConn is null");
}
}
public override string GetUserId(Controller controller)
{
/* TODO - Get UserId from form post */
return controller.User.Identity.Name;
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
Controller
public class CalendarController : Controller
{
CalendarService service;
string CLIENT_ID = ConfigurationManager.AppSettings["GoogleClientID"].ToString();
string CLIENT_SECRET = ConfigurationManager.AppSettings["GoogleClientSecret"].ToString();
[Authorize]
public async Task<ActionResult> CalendarAsync(CancellationToken cancellationToken)
{
ViewBag.Message = "Your calendar page.";
var result = await new AuthorizationCodeMvcApp(this, new AppAuthFlowMetadata(
new SqlConnection(ConfigurationManager.ConnectionStrings["HFConnString"].ConnectionString),
CLIENT_ID,
CLIENT_SECRET)
).AuthorizeAsync(cancellationToken);
if (result.Credential == null)
return new RedirectResult(result.RedirectUri);
service = new CalendarService(new BaseClientService.Initializer
{
HttpClientInitializer = result.Credential,
ApplicationName = "ASP.NET Google APIs MVC Sample"
});
...
}
}