14

iOSアプリケーションでAmazonのProductAdvertisingAPIにアクセスしようとしています。署名の作成は難しい部分のようです。このページ:

http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/rest-signature.html

「SHA256ハッシュアルゴリズムを使用してRFC2104準拠のHMACを計算する」と書かれています。Amazonは、これを行うためのJavaクラスも提供しています。

http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/AuthJavaSampleSig2.html

代わりにObjective-Cでこれを行う方法を知っている人はいますか?AWS iOS SDKを調べましたが、ProductAdvertisingAPIが含まれていないようです。

4

8 に答える 8

11

実際、AWS iOS SDK DID には、すべての認証状況を処理するための静的メソッドがあります。たぶん、次を一瞥する必要がありますAmazonAuthUtils.h

+(NSString *)HMACSign:(NSData *)data withKey:(NSString *)key usingAlgorithm:(CCHmacAlgorithm)algorithm;
+(NSData *)sha256HMac:(NSData *)data withKey:(NSString *)key;

ドキュメントで見つけることができます: http://docs.amazonwebservices.com/AWSiOSSDK/latest/Classes/AmazonAuthUtils.html

于 2012-06-28T08:44:42.510 に答える
11

camelcc の優れた観察に少し追加します。これは実際、Amazon Product Advertising API への署名リクエストにうまく機能します。それを機能させるには、少しいじる必要がありました。

SDK をインストールして、#import <AWSiOSSDK/AmazonAuthUtils.h>

まず、Amazon のドキュメントに従って、リクエスト文字列を正しい順序に整理する必要があります。このページは、リクエストの注文方法を説明するのに非常に役立ちました

http://skilldrick.co.uk/2010/02/amazon-product-information-via-amazon-web-services/

文字列に改行文字が必要であることに注意してください。署名されていない文字列は次のようになりました

@"GET\necs.amazonaws.com\n/onca/xml\nAWSAccessKeyId=<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"

どこにもスペースはありませんが\n、適切な場所に文字があります。NSDatathis をlike soに変換します

NSData *dataToSign = [unsignedString dataUsingEncoding:NSUTF8StringEncoding];

それから電話する

[AmazonAuthUtils HMACSign:dataToSign withKey:SECRET_KEY usingAlgorithm:kCCHmacAlgSHA256]

これにより、署名が として返されますNSString。これを URL エンコードする必要があります (つまり、%0x シンボルの不正/安全でない文字を交換します (つまり、'=' は '%3D' に変換されます))。

これが完了したら、それをリクエストに貼り付けてください。

于 2012-07-03T13:21:50.670 に答える
8

Amazon Product Advertising クライアントをチェックしてください https://github.com/m1entus/RWMAmazonProductAdvertisingManager

リクエストのシリアル化を伴ういくつかのコード:

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;

}
于 2014-04-29T09:21:09.027 に答える
4

Amazon の明示的な書面による同意なしに iOS アプリで Amazon の Product Advertising API を使用することは (Amazon 自身のガイドラインによると) 「合法」ではないというのは間違っていますか?

于 2013-03-14T03:14:18.833 に答える
4

P-double ポストからいくつかのステップが欠落しています。

署名されていない文字列を作成する前に、Timestamp 値を取得する必要があります。

NSTimeZone *zone = [NSTimeZone defaultTimeZone];                //get the current application default time zone
NSInteger interval = [zone secondsFromGMTForDate:[NSDate date]];//sec Returns the time difference of the current application with the world standard time (Green Venice time)

NSDate *nowDate = [NSDate dateWithTimeIntervalSinceNow:interval];
NSDateFormatter * formatter = [[NSDateFormatter alloc] init];

[formatter setTimeZone:[NSTimeZone systemTimeZone]];// get current date/time
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];

// display in 12HR/24HR (i.e. 11:25PM or 23:25) format according to User Settings
[dateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
NSString *currentTime = [dateFormatter stringFromDate:nowDate];

NSString* encodedTime = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef) currentTime,NULL, CFSTR("!*'();:@&=+$,/?%#[]"),kCFStringEncodingUTF8));

NSString* unsignedString = [NSString stringWithFormat:@"GET\nwebservices.amazon.com\n/onca/xml\nAWSAccessKeyId=AKIAI443QEMWI6KW55QQ&AssociateTag=sajjmanz-20&Condition=All&IdType=ASIN&ItemId=3492264077&Operation=ItemLookup&ResponseGroup=Images%%2CItemAttributes%%2COffers&Service=AWSECommerceService&Timestamp=%@&Version=2011-08-01", encodedTime];

日付が URL フレンドリにエンコードされると、残りの手順は魅力的に機能します。

最後に、上記の CFURLCreateStringByAddingPercentEscapes も使用して、AmazonAuthUtils HMACSign メッセージ呼び出しによって生成された文字列をエンコードしました。

于 2013-02-21T10:06:53.933 に答える
3

Instead of using CommonCrypto, which is deprecated in modern OS X, you can also use SecTransforms:

CFErrorRef error = NULL;

SecTransformRef digestRef = SecDigestTransformCreate(kSecDigestHMACSHA2, 256, &error);
SecTransformSetAttribute(digestRef, kSecTransformInputAttributeName, (__bridge CFDataRef)self, &error);
SecTransformSetAttribute(digestRef, kSecDigestHMACKeyAttribute, (__bridge CFDataRef)key, &error);

CFDataRef resultData = SecTransformExecute(digestRef, &error);
NSData* hashData = (__bridge NSData*)resultData;

CFRelease(digestRef);
于 2015-01-22T13:01:45.220 に答える