2012-08-27 123 views
0

我從後複製的代碼:谷歌API的OAuth2.0 JWT返回400 - 錯誤的請求

Google OAuth2 Service Account Access Token Request gives 'Invalid Request' Response

,並試圖讓自己的OAuth2.0/JWT認證工作。但無論我嘗試做什麼,我都會收到異常

System.Exception:遠程服務器返回錯誤:(400)錯誤的請求。

這裏是我的代碼:

public void Authenticate() 
{ 
    string clientId = "...apps.googleusercontent.com"; 
    string clientSecret = "..."; 
    string emailAddress = "[email protected]"; 
    string publicKeyFingerprints = "..."; 

    string certificateFilename = "Google Analytics - OAuth 2.0 - ...-privatekey.p12"; 

    // certificate 
    var certificate = new X509Certificate2(certificateFilename, clientSecret); 

    // header 
    var header = new { typ = "JWT", alg = "RS256" }; 

    // claimset 
    var times = GetExpiryAndIssueDate(); 
    var claimset = new 
    { 
     iss = emailAddress, 
     scope = "https://www.googleapis.com/auth/analytics.readonly", 
     aud = "https://accounts.google.com/o/oauth2/token", 
     iat = times[0], 
     exp = times[1], 
    }; 

    // encoded header 
    var headerSerialized = JsonConvert.SerializeObject(header); 
    var headerBytes = Encoding.UTF8.GetBytes(headerSerialized); 
    var headerEncoded = Base64UrlEncode(headerBytes); 

    // encoded claimset 
    var claimsetSerialized = JsonConvert.SerializeObject(claimset); 
    var claimsetBytes = Encoding.UTF8.GetBytes(claimsetSerialized); 
    var claimsetEncoded = Base64UrlEncode(claimsetBytes); 

    // input 
    var input = headerEncoded + "." + claimsetEncoded; 
    var inputBytes = Encoding.UTF8.GetBytes(input); 

    // signiture 
    var rsa = certificate.PrivateKey as RSACryptoServiceProvider; 
    var cspParam = new CspParameters 
    { 
     KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName, 
     KeyNumber = rsa.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2 
    }; 
    var aescsp = new RSACryptoServiceProvider(cspParam) { PersistKeyInCsp = false }; 
    var signatureBytes = aescsp.SignData(inputBytes, "SHA256"); 
    var signatureEncoded = Base64UrlEncode(signatureBytes); 

    // jwt 
    var jwt = headerEncoded + "." + claimsetEncoded + "." + signatureEncoded; 

    _logger.DebugFormat("JWT: {0}", jwt); 

    var r = WebRequest.Create("https://accounts.google.com/o/oauth2/token") as HttpWebRequest; 
    r.Method = "POST"; 
    r.ContentType = "application/x-www-form-urlencoded"; 

    var post = string.Format("{0}={1}&{2}={3}", 
     "grant_type", HttpUtility.UrlEncode("urn:ietf:params:oauth:grant-type:jwt-bearer", Encoding.UTF8), 
     "assertion" , jwt); 

    var result = SendHttpRequest(r, post); 

    _logger.Debug(result); 
} 

private static int[] GetExpiryAndIssueDate() 
{ 
    var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 
    var issueTime = DateTime.Now; 

    var iat = (int)issueTime.Subtract(utc0).TotalSeconds; 
    var exp = (int)issueTime.AddMinutes(55).Subtract(utc0).TotalSeconds; 

    return new[] { iat, exp }; 
} 

private static string Base64UrlEncode(byte[] input) 
{ 
    var output = Convert.ToBase64String(input); 
    output = output.Split('=')[0]; // Remove any trailing '='s 
    output = output.Replace('+', '-'); // 62nd char of encoding 
    output = output.Replace('/', '_'); // 63rd char of encoding 
    return output; 
} 

private string SendHttpRequest(HttpWebRequest request, string json) 
{ 
    string result = string.Empty; 
    try 
    { 
      _logger.DebugFormat("HttpRequest: {0} {1}", request.Method, request.RequestUri); 
      foreach (string header in request.Headers) 
      { 
       _logger.DebugFormat("Header[{0}]: {1}", header, request.Headers[header]); 
      } 
      _logger.DebugFormat("Body: {0}", json); 

      byte[] body = Encoding.UTF8.GetBytes(json); 
      request.ContentLength = body.Length; 

      using (Stream requestStream = request.GetRequestStream()) 
      { 
       requestStream.Write(body, 0, body.Length); 
      } 

      HttpWebResponse response = request.GetResponse() as HttpWebResponse; 
      using (Stream receiveStream = response.GetResponseStream()) 
      { 
       using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8)) 
       { 
        result = readStream.ReadToEnd(); 
       } 
      } 
      _logger.DebugFormat("...done, result={0}", result); 
    } 
    catch (Exception ex) 
    { 
     throw new Exception(ex.Message); 
    } 
    return result; 
} 

有沒有人有什麼不對的代碼的想法?

回答

1

請看看響應的正文。對於400錯誤背後的原因,通常會有更多細節。

如果您從該帖子複製了該代碼,您是否驗證了服務器上的日期/時間是否正確?這是在簽名作爲JWT的一部分時出現錯誤的最常見原因。即使幾秒鐘也算 - 覈實你的時鐘是同步到NTP和/或匹配time.gov。還要確保時區正確。

+0

Thanx的快速回復。 –

+1

我得到錯誤:invalid_grant。 –

+0

我無法將我的時鐘設置爲與NTP同步,因爲它是域的一部分。 –

3

我得到的代碼工作:

var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 
var issueTime = DateTime.Now.ToUniversalTime(); 

我加.ToUniversalTime(),現在我得到了我的訪問令牌。

+0

非常高興聽到你讓它工作! –

0

我都面臨着同樣的問題

回報400 - 錯誤的請求

錯誤:invalid_grant

錯誤描述:壞請求

這背後的主要原因是不正確的時區或日期和時間在請求令牌的服務器 根據您的時區更改它會正常工作

它爲我工作!

相關問題