Amazon Product Advertising API Signature in iOS
I am trying to access Amazon's Product Advertising API in my iOS application. Creating the signature seems to be the tough part. On this page:
http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/rest-signature.html
It says to "Calculate an RFC 2104-compliant HMAC with the SHA256 hash algorithm". Amazon also provides a java class to do this for you:
http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/AuthJavaSampleSig2.html
Does anybody know how I can do this in Objective-C instead? I looked into the AWS iOS SDK, but it doesn't seem to include the Product Advertising API.
Actually the AWS iOS SDK DID have a static method to handle all auth situations. Maybe you should take a glance at the AmazonAuthUtils.h
:
+(NSString *)HMACSign:(NSData *)data withKey:(NSString *)key usingAlgorithm:(CCHmacAlgorithm)algorithm;
+(NSData *)sha256HMac:(NSData *)data withKey:(NSString *)key;
you can find it in the document: http://docs.amazonwebservices.com/AWSiOSSDK/latest/Classes/AmazonAuthUtils.html
Just to add a bit to camelcc's excellent observation. This does indeed work well for signing requests to the Amazon Product Advertising API. I had to mess around a bit to get it working.
Get the SDK installed and #import <AWSiOSSDK/AmazonAuthUtils.h>
First you've got to organize the request string into the correct order, as per the Amazon docs. I found this page very useful in explaining how to order the request
http://skilldrick.co.uk/2010/02/amazon-product-information-via-amazon-web-services/
Note the need for new-line characters in the string, my unsigned string looked like this
@"GETnecs.amazonaws.comn/onca/xmlnAWSAccessKeyId=<ACCESS_KEY_ID>&AssociateTag=<ASSOCIATE_ID>&Keywords=harry%20potter&Operation=ItemSearch&SearchIndex=Books&Service=AWSECommerceService&Timestamp=2012-07-03T10%3A52%3A21.000Z&Version=2011-08-01"
No spaces anywhere, but n
characters in the right places. The convert this to NSData
like so
NSData *dataToSign = [unsignedString dataUsingEncoding:NSUTF8StringEncoding];
Then call
[AmazonAuthUtils HMACSign:dataToSign withKey:SECRET_KEY usingAlgorithm:kCCHmacAlgSHA256]
This returns your signature as an NSString
. You'll need to URL encode this (ie swapping illegal/unsafe charecters for %0x symbols (ie '=' converts to '%3D'))
Once this is done, stick it in your request and hopefully you are good to go!
Check out my Amazon Product Advertising Client https://github.com/m1entus/RWMAmazonProductAdvertisingManager
Some code with requesst serialization:
NSString * const RWMAmazonProductAdvertisingStandardRegion = @"webservices.amazon.com";
NSString * const RWMAmazonProductAdvertisingAWSAccessKey = @"AWSAccessKeyId";
NSString * const RWMAmazonProductAdvertisingTimestampKey = @"Timestamp";
NSString * const RWMAmazonProductAdvertisingSignatureKey = @"Signature";
NSString * const RWMAmazonProductAdvertisingVersionKey = @"Version";
NSString * const RWMAmazonProductAdvertisingCurrentVersion = @"2011-08-01";
NSData * RWMHMACSHA256EncodedDataFromStringWithKey(NSString *string, NSString *key) {
NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
CCHmacContext context;
const char *keyCString = [key cStringUsingEncoding:NSASCIIStringEncoding];
CCHmacInit(&context, kCCHmacAlgSHA256, keyCString, strlen(keyCString));
CCHmacUpdate(&context, [data bytes], [data length]);
unsigned char digestRaw[CC_SHA256_DIGEST_LENGTH];
NSUInteger digestLength = CC_SHA256_DIGEST_LENGTH;
CCHmacFinal(&context, digestRaw);
return [NSData dataWithBytes:digestRaw length:digestLength];
}
NSString * RWMISO8601FormatStringFromDate(NSDate *date) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
[dateFormatter setDateFormat:@"YYYY-MM-dd'T'HH:mm:ss'Z'"];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
return [dateFormatter stringFromDate:date];
}
NSString * RWMBase64EncodedStringFromData(NSData *data) {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
return [data base64EncodedStringWithOptions:0];
#else
return [data base64Encoding];
#endif
}
//http://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError * __autoreleasing *)error
{
NSParameterAssert(request);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
if (self.accessKey && self.secret) {
NSMutableDictionary *mutableParameters = [parameters mutableCopy];
NSString *timestamp = RWMISO8601FormatStringFromDate([NSDate date]);
if (!mutableParameters[RWMAmazonProductAdvertisingAWSAccessKey]) {
[mutableParameters setObject:self.accessKey forKey:RWMAmazonProductAdvertisingAWSAccessKey];
}
mutableParameters[RWMAmazonProductAdvertisingVersionKey] = RWMAmazonProductAdvertisingCurrentVersion;
mutableParameters[RWMAmazonProductAdvertisingTimestampKey] = timestamp;
NSMutableArray *canonicalStringArray = [[NSMutableArray alloc] init];
for (NSString *key in [[mutableParameters allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
id value = [mutableParameters objectForKey:key];
[canonicalStringArray addObject:[NSString stringWithFormat:@"%@=%@", key, value]];
}
NSString *canonicalString = [canonicalStringArray componentsJoinedByString:@"&"];
canonicalString = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(__bridge CFStringRef)canonicalString,
NULL,
CFSTR(":,"),
kCFStringEncodingUTF8));
NSString *method = [request HTTPMethod];
NSString *signature = [NSString stringWithFormat:@"%@n%@n%@n%@",method,self.region,self.formatPath,canonicalString];
NSData *encodedSignatureData = RWMHMACSHA256EncodedDataFromStringWithKey(signature,self.secret);
NSString *encodedSignatureString = RWMBase64EncodedStringFromData(encodedSignatureData);
encodedSignatureString = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(__bridge CFStringRef)encodedSignatureString,
NULL,
CFSTR("+="),
kCFStringEncodingUTF8));
canonicalString = [canonicalString stringByAppendingFormat:@"&%@=%@",RWMAmazonProductAdvertisingSignatureKey,encodedSignatureString];
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", canonicalString]];
} else {
if (error) {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: NSLocalizedStringFromTable(@"Access Key and Secret Required", @"RWMAmazonProductAdvertisingManager", nil)};
*error = [[NSError alloc] initWithDomain:RWMAmazonProductAdvertisingManagerErrorDomain code:NSURLErrorUserAuthenticationRequired userInfo:userInfo];
}
}
return mutableRequest;
}
链接地址: http://www.djcxy.com/p/38962.html
下一篇: iOS中的亚马逊产品广告API签名