Использование подписанного запроса геокодирования API Карт Google из приложения командной строки .NET - PullRequest
6 голосов
/ 25 января 2012

Итак, я пишу приложение для кэширования данных геокодирования при импорте записей.У меня это работает нормально, когда я использую неподписанный запрос, однако я не могу понять, что не так, когда я пытаюсь использовать клиентские данные и подпись моей компании.Я всегда получаю 403 Запрещено.

Вот мой конструктор URL:

    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;

    } 

Вот программа:

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

Теперь моя первоначальная реакция на это не работалачто Google должен отсутствовать домен реферера, потому что они должны быть зарегистрированы.Поэтому я попытался сделать это с помощью HttpWebRequest и установил реферер в моем домене, но все еще без кубиков.

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

Любая помощь будет высоко ценится.

Ответы [ 4 ]

5 голосов
/ 03 июня 2013
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);
4 голосов
/ 26 января 2012

URL-кодирование иногда необходимо (см. Ниже), но недостаточно. Ваша проблема в том, что вы на самом деле не подписываете свои запросы.

Значение в вашей константе _googleSignature является не подписью, а вашим закрытым криптографическим ключом , что неверно. Ваш закрытый криптографический ключ никогда не должен быть частью какого-либо запроса.

Вместо этого вам нужно использовать его для создания новой подписи для каждого уникального запроса. Пожалуйста, ознакомьтесь с документацией Maps API для бизнес-аутентификации , в нее также входит пример Подписание URL в Java :)

При подписании запросов к веб-службам API Карт Google с помощью идентификатора клиента Maps API для бизнеса и вашего личного криптографического ключа заголовок Referer и IP-адрес источника не имеют значения;)

Кодировка URL необходима только для параметра address, как часть Создание действительного URL . Вы никогда не должны кодировать свою подпись с помощью URL-адреса, поскольку она уже безопасна для URL с использованием модифицированного Base64 для URL-адресов.

0 голосов
/ 26 января 2012

Я думаю, что они проверит, соответствует ли Ip-запрос запросу домена, для которого была зарегистрирована подпись.

Можете ли вы попробовать отправить запрос с вашего веб-сервера?

0 голосов
/ 25 января 2012

Возможно, вам нужно правильно URL-кодировать параметры, прежде чем подставлять их в строку запроса. Вы можете использовать HttpUtility.UrlEncode , если хотите импортировать сборку System.Web (а не использовать клиентский профиль .NET) или можете включить или позаимствовать код из Microsoft Web Protection Library , чтобы сделать это.

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