April 17, 2023
S3 に Access Key ID と Secret Access Key でファイルアップロードする
Dart で AWS S3 にファイルアップロードを行う方法をまとめる。Amplify や Cognito を使った手順はネット上に多数あるが Access Key ID と Secret Access Key を使って直接アップロードする方法はあまりなかったので公開する(Dart 向けに公式の AWS SDK は無いようなので、公式パッケージ持ってきてはい終わり、とはならなかった)。
まず、AWS 上で事前準備を行う。ここは実装に使う言語に依存しない部分。具体的には以下の通り。
IAM でユーザーに与える権限は以下の通り。Web UI 上でポリシー作成時に書き込み可を選択して作成。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:CreateAccessPoint",
"s3:SubmitMultiRegionAccessPointRoutes",
"s3:PutAnalyticsConfiguration",
"s3:PutAccelerateConfiguration",
"s3:PutAccessPointConfigurationForObjectLambda",
"s3:DeleteObjectVersion",
"s3:RestoreObject",
"s3:DeleteAccessPoint",
"s3:CreateBucket",
"s3:DeleteAccessPointForObjectLambda",
"s3:ReplicateObject",
"s3:PutEncryptionConfiguration",
"s3:DeleteBucketWebsite",
"s3:AbortMultipartUpload",
"s3:PutLifecycleConfiguration",
"s3:UpdateJobPriority",
"s3:DeleteObject",
"s3:CreateMultiRegionAccessPoint",
"s3:DeleteBucket",
"s3:PutBucketVersioning",
"s3:PutIntelligentTieringConfiguration",
"s3:PutMetricsConfiguration",
"s3:PutBucketOwnershipControls",
"s3:PutReplicationConfiguration",
"s3:DeleteMultiRegionAccessPoint",
"s3:PutObjectLegalHold",
"s3:InitiateReplication",
"s3:UpdateJobStatus",
"s3:PutBucketCORS",
"s3:PutInventoryConfiguration",
"s3:PutObject",
"s3:PutBucketNotification",
"s3:DeleteStorageLensConfiguration",
"s3:PutBucketWebsite",
"s3:PutBucketRequestPayment",
"s3:PutObjectRetention",
"s3:PutBucketLogging",
"s3:CreateAccessPointForObjectLambda",
"s3:PutBucketObjectLockConfiguration",
"s3:ReplicateDelete"
],
"Resource": "arn:aws:s3:::{your bucket name}/*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": ["s3:PutStorageLensConfiguration", "s3:CreateJob"],
"Resource": "*"
}
]
}
Dart のコードは aws_signature_v4/example を参考に実装。S3 へのファイルアップロード部分だけ参考にする。
必要な Dart パッケージを取得するために pubspec.yaml に以下を追記し、pub get する。
...
dependencies:
aws_common: '>=0.4.0 <0.5.0'
aws_signature_v4: '>=0.3.1+2 <0.4.0'
path: ^1.8.3
...
aws_common や aws_signature_v4 はバージョンを上げすぎると動作しなくなるため注意。代わりに minio を使った方法が Flutter から S3 を操作する ① -設定編- で紹介されており参考になる。
ファイルアップロードの Dart 実装は以下になる。uploadFile 関数を外部のファイルから呼び出す形で記述している。
import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:aws_common/aws_common.dart';
import 'package:aws_signature_v4/aws_signature_v4.dart';
const signer = AWSSigV4Signer(
credentialsProvider: AWSCredentialsProvider(AWSCredentials(
"YOUR AWS ACCESS KEY ID", "YOUR AWS SECRET KEY")),
);
// Set up S3 values
final region = 'ap-northeast-1';
final bucket = 'YOUR BUCKET NAME';
final host = '$bucket.s3.$region.amazonaws.com';
final scope = AWSCredentialScope(
region: region,
service: AWSService.s3,
);
final serviceConfiguration = S3ServiceConfiguration();
Future<void> uploadFile(String filename) async {
final file = File(filename).openRead();
final path = '/${p.basename(filename)}';
final request = AWSStreamedHttpRequest.put(
Uri.https(host, path),
body: file,
headers: {
AWSHeaders.host: host,
AWSHeaders.contentType: 'text/plain',
},
);
stdout.writeln('Uploading file $filename to $path...');
final signedRequest = await signer.sign(
request,
credentialScope: scope,
serviceConfiguration: serviceConfiguration,
);
final uploadResponse = await signedRequest.send().response;
final uploadStatus = uploadResponse.statusCode;
stdout.writeln('Upload File Response: $uploadStatus');
if (uploadStatus != 200) {
exitWithError('Could not upload file');
}
stdout.writeln('File uploaded successfully!');
}
/// Exits the script with an [error].
Never exitWithError(String error) {
stderr.writeln(error);
exit(1);
}
以上。