私の検索方法が悪かったのか、参考になるWebページがあまり見つからなくて困った(>_<) 結局、一番分かり易い、というかクリティカルなところを解決してくれたのはAmazonのコミュニティだった。
やっぱり大事なんだな、こういうところ。
AS3でHMAC-SHA256署名を行うにあたり、まずは以下のパッケージを導入する必要がある。
as3crypto
zipファイルをダウンロードして解凍。
com以下を作業用ディレクトリにコピペ。
後は、このパッケージのHMAC、SHA256、Base64クラスをインポートして、HMAC-SHA256でハッシュ化した後、Base64エンコードする。
この辺の手順については、RHC2104の仕様とか全然読んでない;;
Pythonの時にお世話になった以下のページを参考にハッシュ化とエンコードを行った。
Amazon Product Advertising APIの署名認証をPythonでやってみる
以下、参考までにAS3のソースを公開。
/*** Import ***/
import com.hurlant.crypto.hash.HMAC;
import com.hurlant.crypto.hash.SHA256;
import com.hurlant.util.Base64;
/*** Field Variables ***/
private var requestUri:String = "ecs.amazonaws.jp"
private var requestPath:String = "/onca/xml"
private var amazonSecretKey:String = "AWSの秘密鍵"
/*** AWS Access Method ***/
private function sendAmazonRequest(var1:int, asin:String):void{
var amazonloader:URLLoader = new URLLoader()
// タイムスタンプの作成:ISOフォーマット、UTC(世界標準時)
// make Timestamp: ISO format, UTC
var timestamp:String = makeTimeStamp()
// バイトコード順にソートしつつ、クエリを連結
// クエリをそれぞれescape関数でURLエンコードしておく(×escapeMultiByte)
// sort query by the byte code ascending, and join them
// query is urlencoded by 'escape' method (not escapeMultiByte)
var query:String = "AWSAccessKeyId=Amazonへのアクセスキー&"
+ "ItemId=" + asin + "&"
+ "Operation=ItemLookup&"
+ "ResponseGroup=" + escape("Medium,Images,EditorialReview,Reviews") + "&"
+ "Service=AWSECommerceService&"
+ "Timestamp=" + escape(timestamp) + "&"
+ "Version=" + "2008-08-19";
// 署名の生成
// make Signature
var signatureText:String = ["GET", requestUri, requestPath, query].join("\n") // 署名する文書 Document for signature
var signature:String = makeSignature(signatureText, amazonSecretKey)
// URLエンコードした署名をクエリの最後に追加
// リクエストURLの完成
// add urlencoded Signature to query tail
// complete request Url
query += "&Signature=" + signature.replace(/\+/g,'%2B').replace('=', '%3D')
var requestUrl:String = "http://" + requestUri + requestPath + "?" + query
// amazonへアクセス(onAmazonRequestCompleteにてダウンロード完了後の処理を行う)
// access to Amazon (after download complete, onAmazonRequestComplete() executed)
amazonloader.addEventListener(Event.COMPLETE, onAmazonRequestComplete(var1, amazonloader));
amazonloader.load(new URLRequest());
}
private function makeTimeStamp():String{
// ISOフォーマットでタイムスタンプを生成 YYYY-MM-DDTHH:mm:ss
// 世界標準時(UTC)を採用
var timestamp:String = timeStamper.getUTCFullYear() + "-"
+ to2size(timeStamper.getUTCMonth() + 1) + "-"
+ to2size(timeStamper.getUTCDate()) + "T"
+ to2size(timeStamper.getUTCHours()) + ":"
+ to2size(timeStamper.getUTCMinutes()) + ":"
+ to2size(timeStamper.getUTCSeconds())
return timestamp
}
private function to2size( data:Number ):String{
// 日付や時分秒が10未満の場合、2桁となるよう左に0を挿入
var strData:String = data.toString() // 返却する文字列
if (data < 10) {
strData = "0" + strData
}
return strData
}
private function makeSignature(signatureText:String, key:String):String{
// HMAC-SHA256署名の作成
// 署名する文書と、ハッシュキーを引数として受取り、String型の署名データを返す
// generate HMAC-SHA256 signature
// accept "document for signature(String)" and "signature key(String)" as variables
// return signature(String)
//HMAC-SHA256署名を行うクラス
var hmac256:HMAC = new HMAC(new SHA256());
// 署名する文書のバイトデータ ByteArray for signatured document
var signatureTextBytes:ByteArray = new ByteArray();
signatureTextBytes.writeUTFBytes(signatureText)
// 署名用のハッシュキーのバイトデータ ByteArray for signature key (AWS secret key)
var keyBytes:ByteArray = new ByteArray();
keyBytes.writeUTFBytes(key)
// HMAC-SHA256署名を行い、ダイジェストを生成
// generate Digest (HMAC-SHA256)
var digest256:ByteArray = hmac256.compute(keyBytes, signatureTextBytes);
// ダイジェストをBase64でString型にエンコード
// encode Digest(ByteArray) to String by Base64encoding
var signature:String = Base64.encodeByteArray(digest256)
return signature
}
BeteArrayをnewしてから、writeUTFBytesで中身を書き込むのが味噌。
as3cryptoのテストコードではHexというクラスをnewして、Hex.toArray("署名したいドキュメント")でByteArray型の値を生成していたんだけど、こちらを使うとSignatureが不正になってしまった。
SignatureのURLエンコードはreplaceメソッドで手作業。。。
最初はescape関数を使ってたんだけど、+が上手く%2Bに変換されないんだよね。
エラー続発につき、とりあえず+と=だけ変換するように改良。
ちなみに、ダウンロード終了後に呼び出すイベントハンドラ、onAmazonRequestCompleteメソッドには複数の引数を与えてる。
amazonloader.addEventListener(Event.COMPLETE, onAmazonRequestComplete(var1, amazonloader));
これは、以下のように、イベントハンドラの中で、さらにfunctionをreturnすることで可能となる。
// AmazonのXMLのNamespaceをnewしておく。リクエスト時の"Version"との一致が必須
// make Amazon XML Namespace instance. Namespace Version needs to be as same as "Version" at request
private var ns:Namespace = new Namespace("http://webservices.amazon.com/AWSECommerceService/2008-08-19");
// ダウンロード終了イベントを受け取るメソッド
// Method accepting download complete event
private function onAmazonRequestComplete(var1:int, amazonloader:URLLoader):Function{
// 実際にイベントを処理するfunctionを返す
// return function which handles Event actually
return function(e:Event):void{
default xml namespace = ns;
var response : XML = new XML(amazonloader.data);
// 以下、XML操作...
// And read and write XML...
}
}
難産だった。。。
2 件のコメント:
同じ事で悩んでたので助かりました!ありがとう!
ちんぷんかんぷんだった、AWSの利用方法ですが、とても参考になりましたー!
ありがとうございました!
コメントを投稿