先日AWSがJavascriptSDKのDeveloperプレビューをローンチしました。
http://aws.typepad.com/aws_japan/2013/11/developer-preview-aws-sdk-for-javascript.html
ということで、S3との連携をやってみました。
基本的な流れは
- Web Federationの設定
2.AWS側の設定(CORS,IAM Role等)
- javascriptコーディング
って感じ。
1. AWS Web Identity Federation
AWS Web Identity Federation ってのは別のWebサービスを利用したID連携のことです。OpenID的なもの?
詳しくはこちら↓
http://docs.aws.amazon.com/STS/latest/UsingSTS/CreatingWIF.html
JavaScriptでKeyとSecretをハードコーディングして指定してしまうやり方も出来るんだけど、
そうするとクレデンシャルが丸見えなので
Roleでアクセスコントロールをかなり厳しくしとかないとNG。
その点Web Identity FederationはOAuthみたいにクレデンシャルを一切外部に公開しないため
セキュアということで、今回はWeb Identity Federationを採用。
facebookあんまり好きじゃないので天下のAmazonさん(Login with Amazon)を利用。
認証アプリの作成方法は
AmazonのDeveloperアカウントをとる
アプリ登録
アプリのAppIDとClientIDをメモ
でOK。
2.AWS側の設定(CORS,IAM Role等)
S3を利用する場合はCORSをバケットに対して設定する。<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>https://localhost</AllowedOrigin>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Web Identity FederationのためのIAM(Role)を作成する。
IAM>Role>Create New Roleで
Role for Web Identity Provider Accessを選択してあとはウィザード形式で作成。
www.amazon.com:app_idはアプリ登録で取得したApp IDを入力。
ポリシーはこんな感じになる。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:DeleteObject",
"s3:GetObject",
"s3:ListBucket",
"s3:PutObject"
],
"Sid": "Stmt1383361580000",
"Resource": [
"arn:aws:s3:::testbucket",
"arn:aws:s3:::testbucket/*"
],
"Effect": "Allow"
}
]
}
詳細はここらへん参照。
作成後は対象Roleのarnをメモ。
3. javascriptコーディング
全ての準備が整ったらあとは書くだけ!こんな感じです。
テキトー&8割型コピペなのでご容赦を。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8"/>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.0.0-rc1.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
var s3BucketName = 'testbucket';
var url_params = get_url_vars();
//認証後も同じページに遷移するため、access_tokenがパラメータに含まれていれば設定
var ACCESS_TOKEN = decodeURIComponent(url_params["access_token"]);
AWS.config.credentials = new AWS.WebIdentityCredentials({
RoleArn: 'input your role arn',
ProviderId: 'www.amazon.com',
WebIdentityToken: ACCESS_TOKEN
});
//S3のバケットに入っているオブジェクト一覧を取得&表示
function listObjs() {
var s3 = new AWS.S3({ params: {Bucket: s3BucketName} });
s3.listObjects(function(error,data) {
if (error === null) {
var html_keys = '';
jQuery.each(data.Contents, function(index, obj) {
html_keys += (index + ': ' + obj.Key + '<br />');
});
jQuery("#objKeys").html(html_keys);
} else {
console.log(error);
}
});
}
//アップロード
function uploadObj() {
var s3 = new AWS.S3({ params: {Bucket: s3BucketName}});
var file = $("#uploadFile")[0].files[0];
s3.putObject({
Key: file.name,
ContentType: file.type,
Body: file,
}, function (err, data) {
console.log(err, data);
});
}
function get_url_vars() {
var vars = new Object, params;
var temp_params = window.location.search.substring(1).split('&');
for(var i = 0; i <temp_params.length; i++) {
params = temp_params[i].split('=');
vars[params[0]] = params[1];
}
return vars;
}
$(function(){
//AmazonでログインするためのClientID設定
window.onAmazonLoginReady = function() {
amazon.Login.setClientId('input your app client id');
};
//Amazonでログインする為のスクリプトの非同期読み込み
(function(d) {
var a = d.createElement('script'); a.type = 'text/javascript';
a.async = true;
a.id = 'amazon-login-sdk';
a.src = 'https://api-cdn.amazon.com/sdk/login1.js?v=3';
d.getElementById('amazon-root').appendChild(a);
})(document);
//ログイン
$('#LoginWithAmazon').click(function() {
options = { scope : 'profile' };
amazon.Login.authorize(options, 'https://localhost/js/aws/test3.html');
return false;
});
//ログアウト
$('#Logout').click(function() {
console.log("logout");
amazon.Login.logout();
});
//S3へアップロード
$("#uploadBtn").click(uploadObj);
});
</script>
</head>
<body>
<div id="amazon-root"></div>
<a href="#" id="LoginWithAmazon">
<img border="0" alt="Login with Amazon"
src="https://images-na.ssl-images-amazon.com/images/G/01/lwa/btnLWA_gold_156x32.png"
width="156" height="32" />
</a>
<a id="Logout">Logout</a>
<button onclick="listObjs()">S3 - List Objects</button>
<div id="objKeys"></div>
<form>
<input type="file" id="uploadFile"/>
<input type="button" value="アップロード" id="uploadBtn">
</form>
</body>
</html>
Role ArnとアプリのClientIDをそれぞれ書き込めば動きます。
JavaScript単体で動くっていうことはS3のStatic Web Hostingにhtml&JS置いて
S3にオブジェクト置いたり、取得したりっていうS3だけで完結するアプリが書けるようになったってこと。
しかもS3だけじゃなくてDynamoDBとかSNSとかモバイル向けのサービスにもアクセス出来る。
やっぱり時代の流れはモバイルか!