2012-07-05 25 views
7

Tôi đang cố gắng tích hợp Lịch Google vào ứng dụng của mình và tôi đang gặp phải một số vấn đề với ủy quyền OAuth khi bỏ qua Chế độ làm mới. Tôi nhận được một AccessToken không có vấn đề, nhưng thuộc tính RefreshToken là null. Xem dòng đánh dấu "LỖI TẠI ĐÂY:" cho nơi tôi đang gặp vấn đềTại sao tôi không nhận được một RefreshToken từ yêu cầu Google OAuth?

My Asp.Net MVC điều khiển (tên OAuthController) trông giống như sau:

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); 
    } 

tôi thấy trong các tài liệu API của Google, mà Tôi cần đảm bảo rằng yêu cầu access_type được đặt thành offline để gửi một RefreshToken. Làm cách nào để đặt giá trị này trong yêu cầu Authenticator của tôi?

+0

Tôi đã rút gọn mã của mình và giờ tôi nhận được lỗi Yêu cầu không hợp lệ 400 khi tìm cách truy vấn Google. –

+0

Tôi đã giải quyết được vấn đề của mình bằng cách mã hóa tay HttpRequests qua lại cho Google. Tôi sẽ vệ sinh và đăng mã dưới dạng câu trả lời –

Trả lời

12

Sau nhiều giờ không quan trọng với DotNetOpenAuthGoogle APIs được xuất bản cho. Net, tôi không nhận được gì nhanh chóng. Tôi quyết định phá vỡ các thư viện và truy cập trực tiếp tại Google REST API với các đối tượng HttpRequest và HttpResponse gốc. đang làm vệ sinh của tôi cho bộ điều khiển MVC của tôi sau:

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); 

    } 

nhờ Big để Kelp cho một chút của mã trong đoạn này.

+2

cảm ơn mã, nó thực sự hoạt động :) –

9

Điều chỉnh GoogleAuthenticationServer.Description để có URI điểm cuối ủy quyền bao gồm ?access_type=offline trong chuỗi truy vấn.

+0

Cảm ơn gợi ý rất hữu ích này 'AuthorizationServerDescription descServer = GoogleAuthenticationServer.Description; descServer.AuthorizationEndpoint = new Uri (descServer.AuthorizationEndpoint.ToString() + "? Access_type = offline"); ' sử dụng nó theo cách này và làm việc cho tôi – RohitWagh

0

Chỉ cần thêm

AccessType = "ẩn",

để GoogleOAuth2AuthenticationOptions() đối tượng.

Các vấn đề liên quan