ADO.NET 实现 Google API IDataStore





5.00/5 (4投票s)
Google API IDataStore 的简单实现,
引言
在过去的几天里,我一直在做一个关于 Google OAuth Gmail API 的项目,但我需要在数据库中存储我的 Google 令牌。由于 Google 的实现只是将通信令牌存储在文件中,因此我必须实现一个自定义类来完成此操作。
背景
Google Gmail API 提供了许多非常有用的服务,但采用了新的 OAuth 安全技术。 尽管这种协议具有更好的安全性,但它迫使我们升级我们的电子邮件系统。
本文没有提供安装 OAuth G-Mail 服务的教程。 如果您需要,我建议您访问 Google 提供的以下链接:https://developers.Google.com/identity/protocols/OAuth2
该服务的基础知识包括以下操作
- 您使用在 Google 开发控制台中注册时获得的凭据向 Gmail API 请求服务。
- 由于此凭据仅用于识别您,因此 Gmail 会返回一个网页登录页面和/或一个网页,该网页允许您在系统中进行身份验证,并授权您程序请求的服务。
- 如果您授权,则会将令牌信息下载到您那里。 通常,此信息由 Google API 管理,并将其存储在您计算机上的存储文件中。
对我们来说,问题在于我们需要将凭据存储在数据库表中。
为此,我们实现了 Google API 提供的 IDataStore
接口,以自定义我们的令牌存储。
Using the Code
我们使用 C# 为 ASP.NET 经典应用程序进行开发。 然后,我们创建一个实现 IDataStore
的类,以将令牌信息存储在我们的数据库中。
该类的代码如下所示
using System;
using System.Data.SqlClient;
using System.Threading.Tasks;
using Google.Apis.Json;
using Google.Apis.Util.Store;
namespace GMailApiQuickStart
{
/// <summary>
/// Store Gmail token in the database
/// The information is stored in table OauthToken
/// OAuth token has only three fields
/// ID UserKey and Token
/// </summary>
public class DbDataStore : IDataStore
{
private readonly string conextionDb;
/// <summary>
/// Constructor. Get the conexion string
/// for your database.
/// </summary>
/// <param name="conexionString"></param>
public DbDataStore(string conexionString)
{
conextionDb = conexionString;
}
#region Implementation of IDataStore
/// <summary>
/// Asynchronously stores the given value for the given key (replacing any existing value).
/// </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.</param>
public Task StoreAsync<T>(string key, T value)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
string contents = NewtonsoftJsonSerializer.Instance.Serialize((object)value);
var conn = new SqlConnection(conextionDb);
var comm = new SqlCommand("SELECT COUNT(*) FROM OAuthToken WHERE UserKey = @Param1", conn);
comm.Parameters.AddWithValue("@Param1", key);
conn.Open();
try
{
var res = comm.ExecuteScalar();
if ((int)res == 0)
{
// Insert token
comm = new SqlCommand("INSERT INTO OAuthToken (UserKey, Token)
VALUES (@Param1, @Param2)", conn);
comm.Parameters.AddWithValue("@Param1", key);
comm.Parameters.AddWithValue("@Param2", contents);
}
else
{
//Update token
comm = new SqlCommand("UPDATE OAuthToken SET Token = @Param2
WHERE UserKey = @Param1", conn);
comm.Parameters.AddWithValue("@Param1", key);
comm.Parameters.AddWithValue("@Param2", contents);
}
var exec = comm.ExecuteNonQuery();
}
finally
{
conn.Close();
}
return TaskEx.Delay(0);
}
/// <summary>
/// Asynchronously deletes the given key. The type is provided here as well
/// because the "real" saved key should
/// contain type information as well, so the data store will be able to store
/// the same key for different types.
/// </summary>
/// <typeparam name="T">
/// The type to delete from the data store.
/// </typeparam>
/// <param name="key">The key to delete.</param>
public Task DeleteAsync<T>(string key)
{
var conn = new SqlConnection(conextionDb);
var comm = new SqlCommand("DELETE OAuthToken WHERE UserKey = @Param1", conn);
comm.Parameters.AddWithValue("@Param1", key);
conn.Open();
try
{
var res = comm.ExecuteScalar();
}
finally
{
conn.Close();
}
return TaskEx.Delay(0);
}
/// <summary>
/// Asynchronously returns the stored value for the given key or <c>null</c> if not found.
/// </summary>
/// <typeparam name="T">The type to retrieve from the data store.</typeparam>
/// <param name="key">The key to retrieve its value.</param>
/// <returns>
/// The stored object.
/// </returns>
public Task<T> GetAsync<T>(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
TaskCompletionSource<T> completionSource = new TaskCompletionSource<T>();
var conn = new SqlConnection(conextionDb);
var comm = new SqlCommand("SELECT Token FROM OAuthToken WHERE UserKey = @Param1", conn);
comm.Parameters.AddWithValue("@Param1", key);
conn.Open();
try
{
var res = comm.ExecuteScalar();
if (res == null || string.IsNullOrWhiteSpace(res.ToString()))
{
completionSource.SetResult(default(T));
}
else
{
completionSource.SetResult(NewtonsoftJsonSerializer
.Instance.Deserialize<T>(res.ToString()));
}
}
catch (Exception ex)
{
completionSource.SetException(ex);
}
finally
{
conn.Close();
}
return completionSource.Task;
}
/// <summary>
/// Asynchronously clears all values in the data store.
/// </summary>
public Task ClearAsync()
{
var conn = new SqlConnection(conextionDb);
var comm = new SqlCommand("TRUNCATE TABLE OAuthToken", conn);
conn.Open();
try
{
var res = comm.ExecuteNonQuery();
}
finally
{
conn.Close();
}
return TaskEx.Delay(0);
}
#endregion
}
}
要使用此类,您需要为其提供您的连接字符串。 我使用 Google API Gmail 快速入门的修改版本进行了测试。 您可以在此处找到原始代码和安装程序。
我在代码中包含了一个脚本,用于在测试环境中进行测试。 当然,您可以更改类中的查询以使其适应您的系统。
要进行测试,我们建议您下载快速入门并安装在您的计算机上,使用本文的附带脚本创建数据库,并对其进行修改。 DbDataStore
类的代码也在 zip 文件中。
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Threading;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Gmail.v1;
using Google.Apis.Gmail.v1.Data;
using Google.Apis.Services;
namespace GMailApiQuickStart
{
// This is a modified version of Gmail API Net Quickstart from Google
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/gmail-dotnet-quickstart.json
static string[] Scopes = { GmailService.Scope.GmailReadonly };
static string ApplicationName = "Gmail API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
var conexion = ConfigurationManager.ConnectionStrings["Google"].ConnectionString;
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new DbDataStore(conexion)).Result;
}
// Create Gmail API service.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define parameters of request.
UsersResource.LabelsResource.ListRequest request = service.Users.Labels.List("me");
// List labels.
IList<Label> labels = request.Execute().Labels;
Console.WriteLine("Labels:");
if (labels != null && labels.Count > 0)
{
foreach (var labelItem in labels)
{
Console.WriteLine("{0}", labelItem.Name);
}
}
else
{
Console.WriteLine("No labels found.");
}
Console.Read();
}
}
}
如果您在调用 GoogleWebAuthorizationBroker
时看到,您将 FileStore
参数更改为本文中描述的 DbDataStore
类。 就这些了!
关注点
您可以扩展这个想法,并将密钥文件也放入您的数据库中。 然后,所有 Google OAuth 的管理都可以转换为数据库,而不是使用系统中的文件。
历史
- 第一版
注意:Google 和 G-Mail 是 Google 的注册商标。