谷歌驱动Api -自定义IDataStore与实体框架

时间:2021-10-08 15:27:10

I implemented my custom IDataStore so that I can store End User Tokens on my database instead of the default implementation, which is saved on FileSystem within %AppData%.

我实现了我的自定义IDataStore,这样我就可以将最终用户令牌存储在我的数据库中,而不是默认的实现,它保存在%AppData%的文件系统中。

public class GoogleIDataStore : IDataStore
{
    ...

    public Task<T> GetAsync<T>(string key)
    {
        TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();

        var user = repository.GetUser(key.Replace("oauth_", ""));

        var credentials = repository.GetCredentials(user.UserId);

        if (key.StartsWith("oauth") || credentials == null)
        {
            tcs.SetResult(default(T));
        }
        else
        {
            var JsonData = Newtonsoft.Json.JsonConvert.SerializeObject(Map(credentials));                
            tcs.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize<T>(JsonData));
        }
        return tcs.Task;
    }   
}

Controller

控制器

public async Task<ActionResult> AuthorizeDrive(CancellationToken cancellationToken)
{
    var result = await new AuthorizationCodeMvcApp(this, new GoogleAppFlowMetadata()).
            AuthorizeAsync(cancellationToken);

    if (result.Credential == null)
        return new RedirectResult(result.RedirectUri);

    var driveService = new DriveService(new BaseClientService.Initializer
    {
        HttpClientInitializer = result.Credential,
        ApplicationName = "My app"
    });

    //Example how to access drive files
    var listReq = driveService.Files.List();
    listReq.Fields = "items/title,items/id,items/createdDate,items/downloadUrl,items/exportLinks";
    var list = listReq.Execute();

    return RedirectToAction("Index", "Home");
}

The issue happens on the redirect event. After that first redirect it works fine.

问题发生在重定向事件上。在第一次重定向之后,它可以正常工作。

I found out that something is different on the redirect event. On the redirect event the T is not a Token Response, but a string. Also, the key is prefixed with "oauth_".

我发现在重定向事件上有不同的东西。在重定向事件中,T不是一个令牌响应,而是一个字符串。同样,键的前缀也是“oauth_”。

So I assume that I should return a different result on the redirect, but I have no clue what to return.

所以我假设我应该在重定向上返回一个不同的结果,但是我不知道返回什么。

The error I get is : Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"State is invalid", Description:"", Uri:""

我得到的错误是:google.apis . auth.oauth2 . response。TokenResponseException: Error:“State is invalid”,Description:“”,Uri:“”

Google Source Code Reference https://code.google.com/p/google-api-dotnet-client/source/browse/Src/GoogleApis.DotNet4/Apis/Util/Store/FileDataStore.cs?r=eb702f917c0e18fc960d077af132d0d83bcd6a88

谷歌源代码引用https://code.google.com/p/goog -api-dotnet-client/ source/browse/src/googleapis.dotnet4/apis/util/store/filedatastore.cs?

https://code.google.com/p/google-api-dotnet-client/source/browse/Src/GoogleApis.Auth/OAuth2/Web/AuthWebUtility.cs?r=eb702f917c0e18fc960d077af132d0d83bcd6a88

https://code.google.com/p/google-api-dotnet-client/source/browse/Src/GoogleApis.Auth/OAuth2/Web/AuthWebUtility.cs?r=eb702f917c0e18fc960d077af132d0d83bcd6a88

Thanks for your help

谢谢你的帮助

2 个解决方案

#1


0  

I am not exactly sure why yours isnt working but this is a copy of the code i use. The full class can be found here DatabaseDatastore.cs

我不太清楚为什么你的代码不工作,但这是我使用的代码的拷贝。可以在这里找到完整的类DatabaseDatastore.cs

/// <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("user id=" + LoginName + ";" +
                                      @"password=" + PassWord + ";server=" + ServerName + ";" +
                                      "Trusted_Connection=yes;" +
                                      "database=" + DatabaseName + "; " +
                                      "connection timeout=30");
            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;
        }

#2


0  

The API stores (at least) two values in your IDataStore. Here is what the authorization process looks like from an empty IDataStore's point of view (note which lines set a value and which lines get a value):

API在IDataStore中存储(至少)两个值。下面是空的IDataStore的视角下的授权过程(注意哪些行设置值,哪些行获得值):

Getting IDataStore value:  MyKey       <= null

Setting IDataStore value:  oauth_MyKey => "http://localhost..."
Setting IDataStore value:  MyKey       => {"access_token":"...

Getting IDataStore value:  oauth_MyKey <= "http://localhost..."
Getting IDataStore value:  MyKey       <= {"access_token":"...

At first, the API tries to find a stored access_token, but there is none in the data store (which just returns null), and the API starts the authorization process. The "oauth_..." key is some state info the API needs during this process, and is normally set before it is retrieved (in my experience).

首先,API尝试查找存储的access_token,但是数据存储中没有(它只返回null),并且API启动授权过程。“oauth_…”键是API在此过程中需要的一些状态信息,通常在检索之前进行设置(根据我的经验)。

However, if your IDataStore never received a value with an "oauth_.." key, and thus has nothing to return, simply return null, and the API should create a new one when needed.

但是,如果您的IDataStore从未收到带有“oauth_..”键的值,因此没有返回的内容,那么只需返回null, API应该在需要时创建一个新的值。

#1


0  

I am not exactly sure why yours isnt working but this is a copy of the code i use. The full class can be found here DatabaseDatastore.cs

我不太清楚为什么你的代码不工作,但这是我使用的代码的拷贝。可以在这里找到完整的类DatabaseDatastore.cs

/// <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("user id=" + LoginName + ";" +
                                      @"password=" + PassWord + ";server=" + ServerName + ";" +
                                      "Trusted_Connection=yes;" +
                                      "database=" + DatabaseName + "; " +
                                      "connection timeout=30");
            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;
        }

#2


0  

The API stores (at least) two values in your IDataStore. Here is what the authorization process looks like from an empty IDataStore's point of view (note which lines set a value and which lines get a value):

API在IDataStore中存储(至少)两个值。下面是空的IDataStore的视角下的授权过程(注意哪些行设置值,哪些行获得值):

Getting IDataStore value:  MyKey       <= null

Setting IDataStore value:  oauth_MyKey => "http://localhost..."
Setting IDataStore value:  MyKey       => {"access_token":"...

Getting IDataStore value:  oauth_MyKey <= "http://localhost..."
Getting IDataStore value:  MyKey       <= {"access_token":"...

At first, the API tries to find a stored access_token, but there is none in the data store (which just returns null), and the API starts the authorization process. The "oauth_..." key is some state info the API needs during this process, and is normally set before it is retrieved (in my experience).

首先,API尝试查找存储的access_token,但是数据存储中没有(它只返回null),并且API启动授权过程。“oauth_…”键是API在此过程中需要的一些状态信息,通常在检索之前进行设置(根据我的经验)。

However, if your IDataStore never received a value with an "oauth_.." key, and thus has nothing to return, simply return null, and the API should create a new one when needed.

但是,如果您的IDataStore从未收到带有“oauth_..”键的值,因此没有返回的内容,那么只需返回null, API应该在需要时创建一个新的值。