【发布时间】:2021-07-12 23:38:51
【问题描述】:
在查看 Google OAuth 库方面相当新,但在 Azure/Exchange OAuth 中花了一段时间。 我们对适配器模式中的各种库进行了包装,因此我们的应用程序代码是一致的并调用相同的方法。这是 Google 的样子
private string _state;
private GoogleAuthorizationCodeFlow _flow;
public GoogleTokenProvider(IOAuthSettings settings, string state, string baseUrl) : base(settings, state, baseUrl)
{
//https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#web-applications-asp.net-mvc
_state = state;
GoogleAuthorizationCodeFlow.Initializer init = new GoogleAuthorizationCodeFlow.Initializer {
ClientSecrets = new ClientSecrets
{
ClientId = settings.ClientId,
ClientSecret = settings.ClientSecret
},
Scopes = this.Scopes,
DataStore = new GoogleTokenStore(settings) //Our implementation - not called yet
};
_flow = new GoogleAuthorizationCodeFlow(init);
}
第一步(一旦构建)是获取启动认证过程的url。
public string GetAuthorizationUrl()
{
//Using Flow
var req = _flow.CreateAuthorizationCodeRequest(this.RedirectUrl);
var baseUrl = req.Build().AbsoluteUri;
baseUrl += "&state=" + this._state;
return baseUrl;
// Manually build request
//StringBuilder builder = new StringBuilder();
//builder.Append("https://accounts.google.com/o/oauth2/v2/auth?");
//builder.AppendFormat("scope={0}", String.Join("+", this.Scopes));
//builder.Append("&access_type=offline&include_granted_scopes=true&response_type=code");
//builder.AppendFormat("&state={0}&", this._state);
//builder.AppendFormat("&redirect_uri={0}", this.RedirectUrl);
//builder.AppendFormat("&client_id={0}", this.settings.ClientId);
//return builder.ToString();
}
这行得通,我们被引导到 OAuth 站点,我们使用我们的 Google 帐户登录。我们的回调被触发,在调试回调的时候,我们得到了代码,传递的状态,并调用了这个方法:
public string AcquireTokenByAuthorizationCode(string code)
{
Google.Apis.Auth.OAuth2.Responses.TokenResponse result = _flow.ExchangeCodeForTokenAsync("userid", code, RedirectUrl, new System.Threading.CancellationToken()).Result;
return result.AccessToken;
}
Error:"invalid_client", Description:"Unauthorized", Uri:""
有两个查询。
- 我不确定“UserId”应该是什么,很多帖子里面只有“userid”或“me”,那它是干什么用的?
- 既然Flow类都是用同样的设置构建的,为什么客户端突然失效了。
提前致谢。
谷歌配置
目的是能够阅读来自该帐户的电子邮件(Gmail)
启用的 API:
- Gmail API
- Google+ API
谷歌数据存储实现
public class GoogleTokenStore : IDataStore
{
private readonly IOAuthSettings _settings;
public GoogleTokenStore(IOAuthSettings settings)
{
this._settings = settings;
}
private Dictionary<string, T> Decode<T>()
{
using (var memoryStream = new MemoryStream())
{
var binaryFormatter = new BinaryFormatter();
memoryStream.Write(_settings.TokenStore, 0, _settings.TokenStore.Length);
memoryStream.Seek(0, SeekOrigin.Begin);
return binaryFormatter.Deserialize(memoryStream) as Dictionary<string, T>;
}
}
private void Encode<T>(Dictionary<string, T> store)
{
using (var memoryStream = new MemoryStream())
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, store);
_settings.TokenStore = memoryStream.ToArray();
}
}
public Task ClearAsync()
{
_settings.TokenStore = null;
return Task.CompletedTask;
}
public Task DeleteAsync<T>(string key)
{
if (_settings.TokenStore == null)
{
return Task.CompletedTask; //THIS IS CALLED, RETURNS HERE
}
var store = Decode<T>();
if (store.ContainsKey(key))
{
store.Remove(key);
Encode<T>(store);
}
return Task.CompletedTask;
}
public Task<T> GetAsync<T>(string key)
{
var store = Decode<T>();
if (store.ContainsKey(key))
{
return Task.FromResult( store[key] );
}
return null;
}
public Task StoreAsync<T>(string key, T value)
{
var store = Decode<T>();
if(store != null)
{
store.Add(key, value);
Encode<T>(store);
}
return Task.CompletedTask;
}
}
Google 错误的堆栈跟踪
at Google.Apis.Auth.OAuth2.Responses.TokenResponse.<FromHttpResponseAsync>d__36.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.Requests.TokenRequestExtenstions.<ExecuteAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.<FetchTokenAsync>d__35.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.<FetchTokenAsync>d__35.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.<ExchangeCodeForTokenAsync>d__30.MoveNext()
我已包含此代码,因为它确实显示了 Delete 被调用,并且在返回 Task.CompletedTask 时出现错误(在初始调用时,商店为空,因此只需返回 Task.CompletedTask
【问题讨论】:
标签: c# oauth-2.0 google-api google-oauth google-api-dotnet-client