因此,当我导入记录时,我正在编写一个缓存地理编码数据的应用程序。当我使用未签名的请求时,我的工作正常,但是当我尝试使用我公司的clientid和签名时,我似乎无法弄清楚出了什么问题。我总是得到403 Forbidden。
这是我的网址构建器:
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;
}
非常感谢任何帮助。
答案 0 :(得分: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 :(得分:4)
有时需要进行网址编码(见下文),但还不够。您的问题是,事实上您并未签署您的请求。
_googleSignature
常量中的值不是签名,而是私有加密密钥,这是不好的。您的私人加密密钥永远不应该成为任何请求的一部分。
相反,您需要使用它为每个唯一请求生成新签名。请参阅Maps API for Business Authentication文档,其中还包含Signing a URL in Java的示例:)
使用Maps API for Business客户端ID和您的私人加密密钥对Google Maps API Web服务的请求进行签名时,Referer标头和源IP地址完全无关;)
只有address
参数才需要进行网址编码,这是Building a Valid URL的一部分。您永远不应对您的签名进行URL编码,因为它已经是URL安全的,因为使用修改后的Base64 for URL。
答案 2 :(得分:0)
在将参数替换为查询字符串之前,您可能需要对参数进行正确的URL编码。如果您愿意导入System.Web程序集(而不使用客户端.NET配置文件),则可以使用HttpUtility.UrlEncode,或者可以包含或借用Microsoft's 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));
答案 3 :(得分:0)
我认为他们会检查请求来自的Ip是否与签名注册的域匹配。
您可以尝试从网络服务器发送请求吗?