やりたいこと
- S3のバケットをWebホスティング用に設定することなく、モバイルアプリケーションにバケット内のオブジェクトをダウンロードさせたい。
- ユーザー登録やログインのようなユーザー管理は行わない
モバイルアプリでCognitoを使って匿名ユーザーとして認証を行い、一時的なキーを作成する。このキーにはS3からのダウンロード権限のみを与え、モバイルアプリはキーを使うことでS3からオブジェクトをダウンロードすることができるようになる。
準備
Identity pool を作成する
Identity poolとはCognitoが作成する認証キーが保存されるところです。ここで何個のキーが発行されたかを確認したり、個別のキーを削除したりすることが可能です。
Identity poolにはIAMロールを関連付けます。Cognitoで作成された認証キーはこのIAMロールによってアクセス可能なAWSリソースを制限されます。
関連付けるIAMロールはUnauthenticated roleとAuthenticated roleの2種類があり、匿名認証時とID認証時で必要な権限を分けることができます。両方ともに同じロールを指定することも可能です。
ロールを作成する
Identity poolを作成する時に関連付けるIAMロールを設定します。先にIAMロールを作っておいて設定することもできますし、Identity poolを作成するプロセスの中でIAMロールを作成することもできます。
どちらの場合でも適切に必要最低限の機能のみを与えるようにすることが重要です。
今回の例としてmy-test-bucket
というバケット内の全てのオブジェクトについて取得のみの権限を与えることを考えます。このようなロールは以下のように設定します。
なお、Statement
の一つ目の要素は最初から設定されている権限で、モバイルアナリティクスやCognito同期機能で使用する権限なので、そのまま残してあります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"mobileanalytics:PutEvents",
"cognito-sync:*"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::my-test-bucket/*"
]
}
]
}
Identity poolが作成できたら、次はアプリケーション側の実装です。
以下はAndroid Studioでの作業手順です。
Dependencyを追加
app/build.gradleのdependencies
ブロックに以下の記述を追加します。
dependencies {
compile 'com.amazonaws:aws-android-sdk-core:2.2.+'
compile 'com.amazonaws:aws-android-sdk-s3:2.2.+'
}
パーミッションを追加
S3と通信をするためにもちろんインターネットパーミッションが必要です。ドキュメントには書いてなかったのですがandroid.permission.ACCESS_NETWORK_STATE
もないとエラーになりました。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Java
ここからはJavaの実装になります。
Cognitoを使用して認証キーを取得するためにはまずCognitoCachingCredentialsProvider
インスタンスを作成します。IDENTITY_POOL_ID
は実際のIdentity poolのIDに置き換えてください。この値はAWSコンソールでCognito→Manage Federated Identities→Identity pool名をクリック→Edit identity poolと辿ると確認できます。
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
IDENTITY_POOL_ID,
Regions.AP_NORTHEAST_1 // Region
);
次に、作成したCognitoCachingCredentialsProvider
を使ってAmazonS3Client
インスタンスを作成します。
AmazonS3Client s3 = new AmazonS3Client(credentialsProvider);
S3からファイルをダウンロードするには、TransferUtility
を使います。
TransferUtility transferUtility = new TransferUtility(s3, getApplicationContext());
TransferObserver observer = transferUtility.download("bucketName", "objectName", targetFile);
まとめると以下のような感じになります。
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
IDENTITY_POOL_ID, // 実際のIdentity poolに置き換える
Regions.AP_NORTHEAST_1);
AmazonS3Client s3 = new AmazonS3Client(credentialsProvider);
TransferUtility transferUtility = new TransferUtility(s3, getApplicationContext());
String bucketName = "my-test-bucket";
String fileName = "test.jpg";
File file = new File(getFilesDir(), fileName);
TransferObserver observer = transferUtility.download(bucketName, fileName, file);
observer.setTransferListener(new TransferListener() {
@Override
public void onStateChanged(int id, TransferState state) {
switch (state) {
case COMPLETED:
// ダウンロード完了時
break;
}
}
@Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
}
@Override
public void onError(int id, Exception ex) {
}
});