我有一個web應用程序,用戶在登錄到我們的系統後,可以訪問一個頁面,授權通過整個OAuth進程訪問gmail。該過程完成後,我接收access_token和refresh_token,並解析用戶的子屬性的id_token並將其保存到數據庫。其目的是通過用戶授權我們的應用程序,然後我們在控制檯應用程序中使用訪問和刷新令牌,然後檢索他們的電子郵件並將其與我們的內部系統同步。如何使用access_token查詢gmail api
在谷歌開發控制檯中,我創建了憑據作爲Web應用程序與適當的重定向uris。瀏覽器授權過程一切正常。然而,當我運行使用訪問令牌中的控制檯應用程序,它會打開一個瀏覽器窗口,一個谷歌的錯誤說
Error: redirect_uri_mismatch
The redirect URI in the request, http://127.0.0.1:57590/authorize/, does not match the ones authorized for the OAuth client.
由於這是一個控制檯應用程序,也沒有重定向URI。這讓我想知道是否需要將憑證設置爲「其他」應用程序類型。我創建了一個新的證書,並用新的證書替換了我的Web應用程序中的密鑰和祕密。當我經歷登錄到我們系統的過程,然後訪問授權頁面時,它一切正常。因此,我回到我的控制檯應用程序(現在使用更新的ID),當它運行時,它會打開一個瀏覽器窗口,要求我登錄谷歌並再次驗證它!我已經完成了第一步。由於這是在應用程序服務器上運行的控制檯應用程序,因此用戶無法與其交互以授權訪問......我認爲這是訪問令牌的全部要點!
這是我的代碼。
處理授權的Web應用程序控制器。
public class GoogleController : Controller
{
private readonly CredentialService _credentialService;
private readonly GoogleEndpoints _endpoints;
private string AuthorizeUrl{ get { return ...; }}
private string AuthorizeResponseUrl{ get { return ...; }}
private string SaveResponseUrl{ get { return ...; }}
public GoogleController()
{
_endpoints = new GoogleEndpoints();
_credentialService = new CredentialService(new CredentialRepository(ConnectionStrings.GeneralInfo));
}
public void Authorize()
{
if (Session["UserID"] == null || Session["Email"] == null)
{
Response.Redirect("~/Login.aspx", true);
Session["LoginSource"] = AuthorizeUrl;
Response.End();
}
else
{
if (Session["SessionId"] == null || Session["SessionId"].ToString().Trim().Length == 0)
Session["SessionId"] = _credentialService.CreateSessionId(Session["UserID"].To<int>());
var url = _endpoints.AuthorizationEndpoint + "?" +
"client_id=" + APIConstants.GMailApiKey + "&" +
"response_type=code&" +
"scope=openid%20email https://www.googleapis.com/auth/gmail.readonly&" +
"redirect_uri=" + AuthorizeResponseUrl + "&" +
"state=" + Session["SessionId"] + "&" +
"login_hint=" + Session["Email"] + "&" +
"access_type=offline&prompt=consent";
Response.Redirect(url);
}
}
public ActionResult AuthorizeResponse()
{
var state = Request.QueryString["state"];
if (state == Session["SessionId"].ToString())
{
var code = Request.QueryString["code"];
var values = new Dictionary<string, object>
{
{"code", code},
{"redirect_uri", AuthorizeResponseUrl},
{"client_id", APIConstants.GMailApiKey},
{"client_secret", APIConstants.GmailApiSecret},
{"grant_type", "authorization_code"},
{"scope", ""}
};
var webmethods = new WebMethods();
var tokenResponse = webmethods.Post(_endpoints.TokenEndpoint, values);
var jobject = JObject.Parse(tokenResponse);
var access_token = jobject.SelectToken("access_token");
var refresh_token = jobject.SelectToken("refresh_token");
var id_token = jobject.SelectToken("id_token");
if (access_token == null || access_token.ToString().Trim().Length == 0)
{
var emailService = new EmailRouterService(new EmailRouterRepository(ConnectionStrings.EmailRouter));
emailService.SendEmail(new Email
{
Body = tokenResponse,
Subject = "Error setting up google for " + Session["Email"] + ". ",
FromAddress = "[email protected]",
ToAddress = "[email protected]"
});
return View(new GoogleAuthResponse(tokenResponse, false));
}
var idTokenEls = id_token.ToString().Split('.');
var idTokenString = base64Decode(idTokenEls[1]);
var id_token_json = JObject.Parse(idTokenString);
var credentials = _credentialService.GetUserCredentials(Session["SessionId"].ToString());
credentials.AccessToken = access_token.ToString();
credentials.RefreshToken = refresh_token.ToString();
credentials.TEEmployeeId = Session["UserId"].To<int>();
credentials.EmailAddress = id_token_json.SelectToken("email").ToString();
credentials.GoogleSubKey = id_token_json.SelectToken("sub").ToString();
_credentialService.SaveUserCredentials(credentials);
return View(new GoogleAuthResponse("Integration successful!", true));
}
return View(new GoogleAuthResponse("Missing state information.", false));
}
public string base64Decode(string data)
{
....
}
}
控制檯應用程序正在使用.net谷歌api庫。
public class GmailUserSync
{
private readonly CredentialService _credentialService;
public GmailUserSync(CredentialService credentialService)
{
_credentialService = credentialService;
}
public void SyncThreads()
{
var secrets = new ClientSecrets
{
ClientId = APIConstants.GMailApiKey,
ClientSecret = APIConstants.GmailApiSecret
};
var credentials = _credentialService.GetAllCredentials();
foreach (var c in credentials)
{
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
secrets,
new[] { GmailService.Scope.GmailReadonly },
c.GoogleSubKey,
CancellationToken.None,
new TenixDataStore(_credentialService)).Result;
var service = new GmailService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "Gmail Integration"
});
var request = service.Users.Messages.List("me");
// List messages.
var messages = request.Execute().Messages;
Console.WriteLine("Messages:");
if (messages != null && messages.Count > 0)
foreach (var message in messages)
{
Console.WriteLine("From : " + message.ThreadId);
}
else
Console.WriteLine("No labels found.");
}
Console.Read();
}
}
和我的IDataStore的實現。
public class TenixDataStore : IDataStore
{
private readonly ICredentialService _service;
public TenixDataStore(ICredentialService credentialService)
{
_service = credentialService;
}
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);
var jObject = JObject.Parse(serialized);
var access_token = jObject.SelectToken("access_token");
var refresh_token = jObject.SelectToken("refresh_token");
if (access_token == null)
throw new ArgumentException("Missing access token");
if (refresh_token == null)
throw new ArgumentException("Missing refresh token");
var credential = _service.GetUserCredentialsFromGoogleSubId(key);
credential.AccessToken = (string) access_token;
credential.RefreshToken = (string) refresh_token;
_service.SaveUserCredentials(credential);
return Task.Delay(0);
}
public Task DeleteAsync<T>(string key)
{
return Task.Delay(0);
}
public Task<T> GetAsync<T>(string googleSubId)
{
var credentials = _service.GetUserCredentialsFromGoogleSubId(googleSubId);
var completionSource = new TaskCompletionSource<T>();
if (!string.IsNullOrEmpty(credentials.RefreshToken))
{
var jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(credentials);
completionSource.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize<T>(jsonData));
}
else
completionSource.SetResult(default(T));
return completionSource.Task;
}
public Task ClearAsync()
{
return Task.Delay(0);
}
}
的GetAsync方法在IDataStore被返回訪問令牌和刷新令牌憑據GoogleWebAuthorizationBroker.AuthorizeAsync和它之後的是,當一個新的瀏覽器中打開要我授權的應用程序。
那麼,我應該在谷歌控制檯中設置爲Web應用類型還是其他類型?而且,既然我遇到了問題,無論我嘗試什麼,我做錯了什麼?
我明白了。我在附加的重定向uri中添加了錯誤信息。最終,我放棄了使用.net google api程序集,並最終編寫了自己的代碼。現在一切都按預期工作。 –
好工作。如果你想幫助別人,你可以發佈你的答案。 – noogui
代碼完成後會執行。謝謝。 –