2012-01-25 30 views
6

Vì vậy, tôi đang viết một ứng dụng để lưu trữ dữ liệu mã hóa địa lý khi tôi nhập bản ghi. Tôi đã có nó làm việc tốt khi tôi sử dụng một yêu cầu unsigned, tuy nhiên tôi không thể có vẻ để tìm ra những gì là sai khi tôi cố gắng sử dụng clientid của công ty và chữ ký của tôi. Tôi luôn bị Cấm 403.Sử dụng yêu cầu mã hóa địa lý API Google Maps đã ký từ Ứng dụng dòng lệnh .NET

Dưới đây là xây dựng URL của tôi:

private const string _googleUri = "http://maps.googleapis.com/maps/api/geocode/xml?address="; 
    private const string _googleClientId = "XXXXXXXX"; 
    private const string _googleSignature = "XXXXXXXXXXXXXXXXXXXXXXXX"; 

//RESOLVED 
    private static String GetGeocodeUri(string address) 
    { 
     ASCIIEncoding encoding = new ASCIIEncoding(); 
     string url = String.Format("{0}{1}&client={2}&sensor=false" 
            , _googleUri 
            , HttpUtility.UrlEncode(address) 
            , _googleClientId); 

     // converting key to bytes will throw an exception, need to replace '-' and '_' characters first. 
     string usablePrivateKey = _googleSignature.Replace("-", "+").Replace("_", "/"); 
     byte[] privateKeyBytes = Convert.FromBase64String(usablePrivateKey); 

     Uri uri = new Uri(url); 
     byte[] encodedPathAndQueryBytes = encoding.GetBytes(uri.LocalPath + uri.Query); 

     // compute the hash 
     HMACSHA1 algorithm = new HMACSHA1(privateKeyBytes); 
     byte[] hash = algorithm.ComputeHash(encodedPathAndQueryBytes); 

     // convert the bytes to string and make url-safe by replacing '+' and '/' characters 
     string signature = Convert.ToBase64String(hash).Replace("+", "-").Replace("/", "_"); 

     // Add the signature to the existing URI. 
     return uri.Scheme + "://" + uri.Host + uri.LocalPath + uri.Query + "&signature=" + signature; 

    } 

Dưới đây là Chương trình:

public static AddressClass GetResponseAddress(string address) 
    { 
     AddressClass GoogleAddress = new AddressClass(); 
     XmlDocument doc = new XmlDocument(); 
     String myUri = GetGeocodeUri(address); 

     try 
     { 
      doc.Load(myUri); 
      XmlNode root = doc.DocumentElement; 
      if (root.SelectSingleNode("/GeocodeResponse/status").InnerText == "OK") 
      { 
       GoogleAddress.Latitude = Double.Parse(root.SelectSingleNode("/GeocodeResponse/result/geometry/location/lat").InnerText); 
       GoogleAddress.Longitude = Double.Parse(root.SelectSingleNode("/GeocodeResponse/result/geometry/location/lat").InnerText); 

      } 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Exception <" + ex.Message + ">"); 

     }   

     return GoogleAddress; 
    } 

Bây giờ, phản ứng ban đầu của tôi để nó không làm việc là Google phải thiếu miền referer vì họ phải được đăng ký . Vì vậy, tôi đã thử nó với HttpWebRequest và thiết lập các referer đến tên miền của tôi, nhưng vẫn không có con xúc xắc.

//Not needed, Just an alternate method 
public static AddressClass GetResponseAddress(string address) 
    { 
     AddressClass GoogleAddress = new AddressClass(); 
     WebClient client = new WebClient(); 
     XmlDocument doc = new XmlDocument(); 
     Uri myUri = new Uri(GetGeocodeUri(address)); 
     HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(myUri); 
     myRequest.Referer = "http://www.myDomain.com/"; 

     //I've even tried pretending to be Chrome 
     //myRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7"; 

     try 
     { 
      doc.Load(myRequest.GetResponse().GetResponseStream()); 
      XmlNode root = doc.DocumentElement; 
      if (root.SelectSingleNode("/GeocodeResponse/status").InnerText == "OK") 
      { 
       GoogleAddress.Latitude = Double.Parse(root.SelectSingleNode("/GeocodeResponse/result/geometry/location/lat").InnerText); 
       GoogleAddress.Longitude = Double.Parse(root.SelectSingleNode("/GeocodeResponse/result/geometry/location/lat").InnerText); 
      } 
     } 
     catch (Exception ex) 
     { 
       Console.WriteLine("Exception <" + ex.Message + ">"); 

     } 

     return GoogleAddress; 
    } 

Mọi trợ giúp sẽ được đánh giá cao.

+1

Tôi gần như chắc chắn điều này sẽ giải quyết các điều khoản dịch vụ cho api được đề cập. Lý do bạn gặp phải vấn đề là vì nó không được thiết kế để sử dụng trong một ứng dụng truyền thống chỉ như một ứng dụng web. Đừng quên không có giới hạn giao dịch trừ khi bạn thanh toán cho Google. –

+0

Google cho phép lưu vào bộ nhớ cache trước khi báo cáo cho các tập dữ liệu lớn miễn là được thực hiện đúng cách .--- (b) Không tìm nạp trước, lưu bộ nhớ đệm hoặc lưu trữ nội dung.Bạn không được tìm nạp trước, lưu trữ hoặc lưu trữ bất kỳ Nội dung nào, ngoại trừ việc bạn có thể lưu trữ: (i) Số lượng Nội dung giới hạn nhằm cải thiện hiệu suất của việc triển khai API Maps nếu bạn tạm thời, an toàn và trong cách thức không cho phép sử dụng Nội dung bên ngoài Dịch vụ; và (ii) bất kỳ mã nhận diện hoặc khóa nội dung nào mà Tài liệu API Maps cụ thể cho phép bạn lưu trữ. – copjon

+0

@Ramhound Ngoài ra, có giới hạn truy vấn là 2.500/ngày mà không phải trả tiền và 100.000 nếu bạn thanh toán. – copjon

Trả lời

4

Mã hóa URL đôi khi cần thiết (xem bên dưới) nhưng không đủ. Vấn đề của bạn là bạn không, trên thực tế, ký yêu cầu của bạn.

Giá trị trong hằng số _googleSignature không phải là chữ ký, nhưng khóa mật mã riêng của bạn, điều này không tốt. Khóa mã hóa riêng của bạn không bao giờ nên là một phần của bất kỳ yêu cầu nào của chính nó.

Thay vào đó, bạn cần sử dụng nó để tạo chữ ký mới cho mọi yêu cầu duy nhất. Vui lòng xem tài liệu Maps API for Business Authentication, nó cũng bao gồm ví dụ cho Signing a URL in Java :)

Khi ký yêu cầu dịch vụ web API Google Maps với ID ứng dụng API Maps cho doanh nghiệp và khóa mật mã riêng của bạn, tiêu đề Referer và địa chỉ IP nguồn hoàn toàn không liên quan;)

Mã hóa URL chỉ cần thiết trên thông số address, như một phần của Building a Valid URL. Bạn không bao giờ nên mã hóa URL chữ ký của mình vì nó đã được an toàn cho URL bằng cách sử dụng Base64 đã sửa đổi cho URL.

+0

Cảm ơn, chưa có cơ hội để thực hiện nó nhưng tôi đã hình dung rằng tôi đã thiếu một cái gì đó như thế này. – copjon

+2

Chỉ cần popped mà vào mã của tôi và nó hoạt động như một say mê! Cảm ơn. Đăng mã cuối cùng ở trên cho bất kỳ ai có thể cần mã đó trong tương lai. – copjon

0

Bạn có thể cần phải mã hóa URL các tham số trước khi thay thế chúng thành chuỗi truy vấn. Bạn có thể sử dụng HttpUtility.UrlEncode nếu bạn sẵn sàng nhập hội nghị System.Web (và không sử dụng hồ sơ khách hàng .NET) hoặc bạn có thể bao gồm hoặc mượn mã từ Microsoft's Web Protection Library để thực hiện việc này.

address = HttpUtility.UrlEncode(address); // better than Replace(" ", "+"); 

return String.Format("{0}{1}&client={2}&sensor=false&signature={3}", 
       _googleUri, address, 
       HttpUtility.UrlEncode(_googleClientId), 
       HttpUtility.UrlEncode(_googleSignature)); 
+0

Cảm ơn mẹo ... nhưng vẫn không hoạt động. – copjon

+0

Cập nhật câu hỏi của bạn với nỗ lực hiện tại của bạn. –

+0

@Ramhound Chắc chắn, cập nhật của nó. – copjon

0

Tôi nghĩ rằng họ sẽ kiểm tra xem yêu cầu của Ip có khớp với tên miền mà chữ ký đã được đăng ký không.

Bạn có thể thử gửi yêu cầu từ máy chủ web của mình không?

+0

Tôi đã nghĩ rằng, tôi chỉ hy vọng làm cho nó hoạt động độc lập với máy tính của nó. – copjon

5
const String gmeClientID = "gme-myClientId"; 
const String key = "myGoogleKey"; 

var urlRequest = String.Format("/maps/api/geocode/json?latlng={0},{1}&sensor=false&client={2}",Latitude,Longitude,gmeClientID); 

HMACSHA1 myhmacsha1 = new HMACSHA1(); 
myhmacsha1.Key = Convert.FromBase64String(key); 
var hash = myhmacsha1.ComputeHash(Encoding.ASCII.GetBytes(urlRequest)); 

var url = String.Format("http://maps.googleapis.com{0}&signature={1}", urlRequest, Convert.ToBase64String(hash).Replace("+", "-").Replace("/", "_")); 

var request = (HttpWebRequest)HttpWebRequest.Create(url); 
+1

Đây thực sự là một ví dụ tuyệt vời về việc triển khai nó, bây giờ tôi đã khắc phục sự cố trong đó khóa không được giải mã từ mã hóa URLSafe của google. Đây chỉ là vấn đề nếu khóa được cung cấp của bạn chứa _ hoặc -, mà google thay đổi thành/hoặc +. Điều này làm cho chúng không còn hợp lệ base64, do đó bạn phải hoàn tác nó trước khi chuyển nó vào 'FromBase64String'. – jep

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