Asp.net-Mvc
為什麼我沒有收到來自 Google OAuth 請求的 RefreshToken?
我正在嘗試將 Google 日曆集成到我的應用程序中,並且在傳遞 RefreshToken 的 OAuth 授權方面遇到了一些問題。我收到一個沒有問題的 AccessToken,但 RefreshToken 屬性為空。請參閱標有“此處錯誤:”的行以了解我遇到問題的位置
我的 Asp.Net MVC 控制器(名為
OAuthController)如下所示:public ActionResult Index() { var client = CreateClient(); client.RequestUserAuthorization(new[] { "https://www.googleapis.com/auth/calendar" }, new Uri("http://localhost/FL.Evaluation.Web/OAuth/CallBack")); return View(); } public ActionResult CallBack() { if (string.IsNullOrEmpty(Request.QueryString["code"])) return null; var client = CreateClient(); // Now getting a 400 Bad Request here var state = client.ProcessUserAuthorization(); // ERROR HERE: The RefreshToken is NULL HttpContext.Session["REFRESH_TOKEN"] = Convert.ToBase64String(Encoding.Unicode.GetBytes(state.RefreshToken)); return JavaScript("Completed!"); } private static WebServerClient CreateClient() { return new WebServerClient( new AuthorizationServerDescription() { TokenEndpoint = new Uri("https://accounts.google.com/o/oauth2/token"), AuthorizationEndpoint = new Uri("https://accounts.google.com/o/oauth2/auth"), ProtocolVersion = ProtocolVersion.V20 } , _GoogleClientId, _GoogleSecret); }我在 Google 的 API 文件中看到,我需要確保將
access_type請求設置offline為發送 RefreshToken。如何在 Authenticator 請求中設置此值?
經過數小時擺弄DotNetOpenAuth和為 .Net 發布的Google API之後,我一無所獲。我決定繞過這些庫,直接使用原生 HttpRequest 和 HttpResponse 對象訪問Google REST API 。我的 MVC 控制器的淨化程式碼如下:
private static string _GoogleClientId = "CLIENT_ID"; private static string _GoogleSecret = "SECRET"; private static string _ReturnUrl = "http://localhost/OAuth/CallBack"; public ActionResult Index() { return Redirect(GenerateGoogleOAuthUrl()); } private string GenerateGoogleOAuthUrl() { //NOTE: Key piece here, from Andrew's reply -> access_type=offline forces a refresh token to be issued string Url = "https://accounts.google.com/o/oauth2/auth?scope={0}&redirect_uri={1}&response_type={2}&client_id={3}&state={4}&access_type=offline&approval_prompt=force"; string scope = UrlEncodeForGoogle("https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/calendar.readonly").Replace("%20", "+"); string redirect_uri_encode = UrlEncodeForGoogle(_ReturnUrl); string response_type = "code"; string state = ""; return string.Format(Url, scope, redirect_uri_encode, response_type, _GoogleClientId, state); } private static string UrlEncodeForGoogle(string url) { string UnReservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"; var result = new StringBuilder(); foreach (char symbol in url) { if (UnReservedChars.IndexOf(symbol) != -1) { result.Append(symbol); } else { result.Append('%' + String.Format("{0:X2}", (int)symbol)); } } return result.ToString(); } class GoogleTokenData { public string Access_Token { get; set; } public string Refresh_Token { get; set; } public string Expires_In { get; set; } public string Token_Type { get; set; } } public ActionResult CallBack(string code, bool? remove) { if (remove.HasValue && remove.Value) { Session["GoogleAPIToken"] = null; return HttpNotFound(); } if (string.IsNullOrEmpty(code)) return Content("Missing code"); string Url = "https://accounts.google.com/o/oauth2/token"; string grant_type = "authorization_code"; string redirect_uri_encode = UrlEncodeForGoogle(_ReturnUrl); string data = "code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type={4}"; HttpWebRequest request = HttpWebRequest.Create(Url) as HttpWebRequest; string result = null; request.Method = "POST"; request.KeepAlive = true; request.ContentType = "application/x-www-form-urlencoded"; string param = string.Format(data, code, _GoogleClientId, _GoogleSecret, redirect_uri_encode, grant_type); var bs = Encoding.UTF8.GetBytes(param); using (Stream reqStream = request.GetRequestStream()) { reqStream.Write(bs, 0, bs.Length); } using (WebResponse response = request.GetResponse()) { var sr = new StreamReader(response.GetResponseStream()); result = sr.ReadToEnd(); sr.Close(); } var jsonSerializer = new JavaScriptSerializer(); var tokenData = jsonSerializer.Deserialize<GoogleTokenData>(result); Session["GoogleAPIToken"] = tokenData.Access_Token; return JavaScript("Refresh Token: " + tokenData.Refresh_Token); }非常感謝Kelp提供了這段程式碼中的一些程式碼。