2012-07-05 40 views
7

我試圖谷歌日曆集成到我的應用程序,我有一些問題OAuth授權假冒一個RefreshToken。我收到一個沒有問題的AccessToken,但RefreshToken屬性爲空。看行「在這裏ERROR:」標誌着在那裏我遇到的問題爲什麼我沒有從Google OAuth請求中收到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); 
    } 

我在谷歌的API文檔看,那我需要確保請求被設置爲offline的RefreshToken的access_type發送。如何在我的身份驗證器請求中設置此值?

+0

我已經瘦身我的代碼下來,並試圖查詢谷歌現在,當我得到一個400錯誤請求錯誤。 – 2012-07-05 19:24:07

+0

我通過手動編寫HttpRequests到Google來解決我的問題。我會消毒及郵政編碼爲答案 – 2012-07-06 11:22:35

回答

12

後與DotNetOpenAuth擺弄小時,Google APIs公佈的.Net,我無處可去快。我決定繞過這些庫,直接使用本地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 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~"; 
     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在這個片段中位代碼。

+2

感謝您的代碼,它真的工作:) – 2014-07-16 14:01:36

9

調整GoogleAuthenticationServer.Description具有授權端點URI包括在查詢字符串?access_type=offline

+0

感謝這個非常有用的提示 'AuthorizationServerDescription descServer = GoogleAuthenticationServer.Description; descServer.AuthorizationEndpoint = new Uri(descServer.AuthorizationEndpoint.ToString()+「?access_type = offline」);' 使用它這種方式併爲我工作 – RohitWagh 2013-06-19 11:07:54

0

只需添加

接入類型= 「離線」,

到GoogleOAuth2AuthenticationOptions()對象。

相關問題