- 问题已解决--请参阅说明末尾的更新2。以下代码很好**
我的头发在这里撕裂...但在这里:
我正试图从API中挂钩到亚马逊Alexa API(http://docs.aws.amazon.com/AlexaWebInfoService/latest/index.html?ApiReference_UrlInfoAction.html)数据...我需要使用C#。
我用Java代码更新了下面的帖子,看看是我的代码问题还是AWIS问题。
关于C#,在这篇文章末尾的家伙声称它已经工作了:www.example.comhttps://forums.aws.amazon.com/message.jspa?messageID=476573#476573
下面是调用该类的C#代码:
var awis = new AmazonAWIS
{
AWSAccessKeyId = "ABCDRFGHIJKLMNOP",
AWSSecret = "GpC0PcXnnzG/TCpoi9r7RxBtqCzdKaHeEkq7Mfs6"
};
awis.UrlInfo("bbc.co.uk");
而这是直接从上面发布的链接中获取的类代码...我没有更改它:
public class AmazonAWIS
{
public string AWSAccessKeyId { get; set; }
public string AWSSecret { get; set; }
protected string GenerateSignature(string param)
{
var sign = "GET\n" + "awis.amazonaws.com" + "\n/\n" + param;
// create the hash object
var shaiSignature = new HMACSHA256(Encoding.UTF8.GetBytes(AWSSecret));
// calculate the hash
var binSig = shaiSignature.ComputeHash(Encoding.UTF8.GetBytes(sign));
// convert to hex
var signature = Convert.ToBase64String(binSig);
return signature;
}
// this is one of the key problems with the Amazon code and C#.. C# by default returns excaped values in lower case
// for example %3a but Amazon expects them in upper case i.e. %3A, this function changes them to upper case..
//
public static string UpperCaseUrlEncode(string s)
{
char[] temp = HttpUtility.UrlEncode(s).ToCharArray();
for (int i = 0; i < temp.Length - 2; i++)
{
if (temp[i] == '%')
{
temp[i + 1] = char.ToUpper(temp[i + 1]);
temp[i + 2] = char.ToUpper(temp[i + 2]);
}
}
return new string(temp);
}
string GetQueryParams(string action, Dictionary<string, string> extra)
{
var time = DateTime.UtcNow;
// set the correct format for the date string
var timestamp = time.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", System.Globalization.CultureInfo.InvariantCulture);
// create a sortable dict
var vals = new Dictionary<string, string>();
vals.Add("AWSAccessKeyId", AWSAccessKeyId);
vals.Add("Action", action);
vals.Add("ResponseGroup", "Rank,ContactInfo,LinksInCount");
vals.Add("Timestamp", timestamp);
vals.Add("Count", "10");
vals.Add("Start", "1");
vals.Add("SignatureVersion", "2");
vals.Add("SignatureMethod", "HmacSHA256");
// add any extra values
foreach (var v in extra)
{
if (vals.ContainsKey(v.Key) == false)
vals.Add(v.Key, v.Value);
}
// sort the values by ordinal.. important!
var sorted = vals.OrderBy(p => p.Key, StringComparer.Ordinal).ToArray();
var url = new StringBuilder();
foreach (var v in sorted)
{
if (url.Length > 0)
url.Append("&");
url.Append(v.Key + "=" + UpperCaseUrlEncode(v.Value));
}
return url.ToString();
}
public void UrlInfo(string domain)
{
string request = "UrlInfo";
// add the extra values
var extra = new Dictionary<string, string>();
extra.Add("Url", domain);
// run the request with amazon
try
{
var res = RunRequest(request, extra);
// process the results...
Console.WriteLine(res);
}
catch (Exception ex)
{
throw;
}
}
private string RunRequest(string request, Dictionary<string, string> extra)
{
// generate the query params
var queryParams = GetQueryParams(request, extra);
// calculate the signature
var sig = GenerateSignature(queryParams);
// generate the url
var url = new StringBuilder();
url.Append("http://awis.amazonaws.com?");
url.Append(queryParams);
url.Append("&Signature=" + UpperCaseUrlEncode(sig));
// get the request
var c = new WebClient();
var res = c.DownloadString(url.ToString());
return res;
}
}
它在以下行失败:
var res = c.DownloadString(url.ToString());
我总是得到401未经授权...
你知道我做错了什么吗?
- 更新**
我可以在他们的Java示例应用程序中重现同样的问题。我已经修改了他们的应用程序,只对AWSAccessId和SecretKey进行硬编码,而且我也没有使用他们应用程序中的sun.misc.BASE64Encoder。
确切的代码如下...同样,如果我从makeRequest(uri)语句中获取uri,粘贴到Fiddler中,我可以看到它是相同的401响应:
<?xml version="1.0"?>
AuthFailure
AWS无法验证提供的访问凭据ff8f1853-b816 - 47a0 - 2283-be9941e7f2a9
和代码,导致上述(我已经改变了accessKey和secretKey):
package urlinfo.com;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.SignatureException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* Makes a request to the Alexa Web Information Service UrlInfo action.
*/
public class UrlInfo {
private static final String ACTION_NAME = "UrlInfo";
private static final String RESPONSE_GROUP_NAME = "Rank,ContactInfo,LinksInCount";
private static final String SERVICE_HOST = "awis.amazonaws.com";
private static final String AWS_BASE_URL = "http://" + SERVICE_HOST + "/?";
private static final String HASH_ALGORITHM = "HmacSHA256";
private static final String DATEFORMAT_AWS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
private String accessKeyId;
private String secretAccessKey;
private String site;
public UrlInfo(String accessKeyId, String secretAccessKey, String site) {
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
this.site = site;
}
/**
* Generates a timestamp for use with AWS request signing
*
* @param date current date
* @return timestamp
*/
protected static String getTimestampFromLocalTime(Date date) {
SimpleDateFormat format = new SimpleDateFormat(DATEFORMAT_AWS);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
return format.format(date);
}
/**
* Computes RFC 2104-compliant HMAC signature.
*
* @param data The data to be signed.
* @return The base64-encoded RFC 2104-compliant HMAC signature.
* @throws java.security.SignatureException
* when signature generation fails
*/
protected String generateSignature(String data)
throws java.security.SignatureException {
String result;
try {
// get a hash key from the raw key bytes
SecretKeySpec signingKey = new SecretKeySpec(
secretAccessKey.getBytes(), HASH_ALGORITHM);
// get a hasher instance and initialize with the signing key
Mac mac = Mac.getInstance(HASH_ALGORITHM);
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(data.getBytes());
// base64-encode the hmac
// result = Encoding.EncodeBase64(rawHmac);
// result = new BASE64Encoder().encode(rawHmac);
result = javax.xml.bind.DatatypeConverter.printBase64Binary(rawHmac);
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : "
+ e.getMessage());
}
return result;
}
/**
* Makes a request to the specified Url and return the results as a String
*
* @param requestUrl url to make request to
* @return the XML document as a String
* @throws IOException
*/
public static String makeRequest(String requestUrl) throws IOException {
URL url = new URL(requestUrl);
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream();
// Read the response
StringBuffer sb = new StringBuffer();
int c;
int lastChar = 0;
while ((c = in.read()) != -1) {
if (c == '<' && (lastChar == '>'))
sb.append('\n');
sb.append((char) c);
lastChar = c;
}
in.close();
return sb.toString();
}
/**
* Builds the query string
*/
protected String buildQuery()
throws UnsupportedEncodingException {
String timestamp = getTimestampFromLocalTime(Calendar.getInstance().getTime());
Map<String, String> queryParams = new TreeMap<String, String>();
queryParams.put("Action", ACTION_NAME);
queryParams.put("ResponseGroup", RESPONSE_GROUP_NAME);
queryParams.put("AWSAccessKeyId", accessKeyId);
queryParams.put("Timestamp", timestamp);
queryParams.put("Url", site);
queryParams.put("SignatureVersion", "2");
queryParams.put("SignatureMethod", HASH_ALGORITHM);
String query = "";
boolean first = true;
for (String name : queryParams.keySet()) {
if (first)
first = false;
else
query += "&";
query += name + "=" + URLEncoder.encode(queryParams.get(name), "UTF-8");
}
return query;
}
/**
* Makes a request to the Alexa Web Information Service UrlInfo action
*/
public static void main(String[] args) throws Exception {
String accessKey = "REMOVED";
String secretKey = "REMOVED";
// String site = args[2];
String site = "www.google.com";
UrlInfo urlInfo = new UrlInfo(accessKey, secretKey, site);
String query = urlInfo.buildQuery();
String toSign = "GET\n" + SERVICE_HOST + "\n/\n" + query;
System.out.println("String to sign:\n" + toSign + "\n");
String signature = urlInfo.generateSignature(toSign);
String uri = AWS_BASE_URL + query + "&Signature=" +
URLEncoder.encode(signature, "UTF-8");
System.out.println("Making request to:\n");
System.out.println(uri + "\n");
// Make the Request
String xmlResponse = makeRequest(uri);
// Print out the XML Response
System.out.println("Response:\n");
System.out.println(xmlResponse);
}
}
- 更新2:**
这段代码没有问题。问题出在AWIS的注册按钮上。使用页面底部的那个...而不是顶部的那个(这是大多数人会点击的)。亚马逊确认顶部的按钮目前不能工作。
1条答案
按热度按时间bwleehnv1#
我收到了同样的错误,通过我的php代码,即使在功能失调的按钮错误被处理。See here
对我来说,这个错误是因为我使用的IAM凭据仍然与AWIS不兼容,并且here没有记录这一点。应该使用AWIS的root帐户详细信息。请参见此处