2012-08-13 36 views
12

Tôi đang cố gắng liên lạc với API BigQuery được bật của ứng dụng thông qua phương thức máy chủ đến máy chủ.Yêu cầu mã thông báo truy cập tài khoản dịch vụ Google OAuth2 đưa ra yêu cầu 'Yêu cầu không hợp lệ'

Tôi đã chọn tất cả các hộp trên số Google guide này để xây dựng JWT của tôi là tốt nhất có thể trong C#.

Và tôi đã Base64Url mã hóa mọi thứ cần thiết.

Tuy nhiên, phản ứng duy nhất tôi nhận được từ google là 400 Bad Request

"error" : "invalid_request" 

Tôi đã thực hiện chắc chắn về tất cả những điều sau đây từ những SO câu hỏi khác:

Tôi nhận được kết quả tương tự khi tôi sử dụng Fiddler. Các thông báo lỗi là bực bội thiếu chi tiết! Tôi có thể thử cái gì nữa ?! Đây là mã của tôi:

class Program 
{ 
    static void Main(string[] args) 
    { 
     // certificate 
     var certificate = new X509Certificate2(@"<Path to my certificate>.p12", "notasecret"); 

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

     // claimset 
     var times = GetExpiryAndIssueDate(); 
     var claimset = new 
     { 
      iss = "<email address of the client id of my app>", 
      scope = "https://www.googleapis.com/auth/bigquery", 
      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; 

     Console.WriteLine(jwt); 

     var client = new HttpClient(); 
     var uri = "https://accounts.google.com/o/oauth2/token"; 
     var post = new Dictionary<string, string> 
     { 
      {"assertion", jwt}, 
      {"grant_type", "urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer"} 
     }; 
     var content = new FormUrlEncodedContent(post); 
     var result = client.PostAsync(uri, content).Result; 

     Console.WriteLine(result); 
     Console.WriteLine(result.Content.ReadAsStringAsync().Result); 
     Console.ReadLine(); 
    } 

    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; 
    } 
} 
+0

Tôi không tìm thấy bất kỳ điều gì rõ ràng, và tôi đã từng bước qua từng dòng mã của bạn. Một điều có thể là bạn đang mã hóa loại trợ cấp trong từ điển của bạn và FormUrlEncodededContent có thể kết thúc mã hóa kép. Vì vậy, tôi sẽ thử "urn: ietf: params: oauth: grant-type: jwt-bearer" để thay thế. –

+1

Hình như HttpClient là từ một bản phát hành .NET framework gần đây, vì vậy tôi cài đặt nó và thử mã trực tiếp. Tôi cũng đã liên hệ nội bộ với một vài người có thể giúp đỡ. –

Trả lời

12

Có vẻ như dự đoán của tôi trong nhận xét ở trên là chính xác. Tôi nhận được mã của bạn làm việc bằng cách thay đổi:

"urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer"

tới:

"urn:ietf:params:oauth:grant-type:jwt-bearer"

Hình như bạn đã vô tình kích đúp mã hóa nó.

bây giờ tôi nhận được một câu trả lời mà trông giống như sau:

{ 
    "access_token" : "1/_5pUwJZs9a545HSeXXXXXuNGITp1XtHhZXXxxyyaacqkbc", 
    "token_type" : "Bearer", 
    "expires_in" : 3600 
} 

Chỉnh sửa Lưu ý: Hãy chắc chắn rằng để có ngày/giờ/múi giờ/cấu hình dst đúng trên máy chủ của bạn. Việc tắt đồng hồ thậm chí một vài giây sẽ dẫn đến lỗi invalid_grant. http://www.time.gov sẽ cung cấp thời gian chính thức từ govt của Hoa Kỳ, bao gồm cả trong UTC.

5

Đảm bảo sử dụng DateTime.UtcNow thay vì DateTime.Now trong phương thức GetExpiryAndIssueDate.

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