Want to upload & fetch media files from AWS S3 in Flutter. There’s a few ways to do this. One way is to sign your request with Signature V4 and POST your file to S3.
First, create a policy helper:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import 'dart:convert'; import 'package:amazon_cognito_identity_dart/sig_v4.dart'; class Policy { String expiration; String region; String bucket; String key; String credential; String datetime; int maxFileSize; Policy(this.key, this.bucket, this.datetime, this.expiration, this.credential, this.maxFileSize, {this.region = 'us-east-1'}); factory Policy.fromS3PresignedPost( String key, String bucket, String accessKeyId, int expiryMinutes, int maxFileSize, { String region, }) { final datetime = SigV4.generateDatetime(); final expiration = (DateTime.now()) .add(Duration(minutes: expiryMinutes)) .toUtc() .toString() .split(' ') .join('T'); final cred = '$accessKeyId/${SigV4.buildCredentialScope(datetime, region, 's3')}'; final p = Policy(key, bucket, datetime, expiration, cred, maxFileSize, region: region); return p; } String encode() { final bytes = utf8.encode(toString()); return base64.encode(bytes); } @override String toString() { return ''' { "expiration": "${this.expiration}", "conditions": [ {"bucket": "${this.bucket}"}, ["starts-with", "\$key", "${this.key}"], {"acl": "public-read"}, ["content-length-range", 1, ${this.maxFileSize}], {"x-amz-credential": "${this.credential}"}, {"x-amz-algorithm": "AWS4-HMAC-SHA256"}, {"x-amz-date": "${this.datetime}" } ] } '''; } } |
Then, sign your request with your policy helper and upload via http.MultipartRequest:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import 'dart:convert'; import 'dart:io'; import 'package:path/path.dart' as path; import 'package:async/async.dart'; import 'package:http/http.dart' as http; import 'package:test/test.dart'; import 'package:amazon_cognito_identity_dart/sig_v4.dart'; import './policy.dart'; void main() { const _accessKeyId = 'AKXXXXXXXXXXXXXXXXXX'; const _secretKeyId = 'xxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxx'; const _region = 'ap-southeast-1'; const _s3Endpoint = 'https://bucketname.s3-ap-southeast-1.amazonaws.com'; final file = File(path.join('/path/to/file', 'square-cinnamon.jpg')); final stream = http.ByteStream(DelegatingStream.typed(file.openRead())); final length = await file.length(); final uri = Uri.parse(_s3Endpoint); final req = http.MultipartRequest("POST", uri); final multipartFile = http.MultipartFile('file', stream, length, filename: path.basename(file.path)); final policy = Policy.fromS3PresignedPost('uploaded/square-cinnamon.jpg', 'bucketname', _accessKeyId, 15, length, region: _region); final key = SigV4.calculateSigningKey(_secretKeyId, policy.datetime, _region, 's3'); final signature = SigV4.calculateSignature(key, policy.encode()); req.files.add(multipartFile); req.fields['key'] = policy.key; req.fields['acl'] = 'public-read'; req.fields['X-Amz-Credential'] = policy.credential; req.fields['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'; req.fields['X-Amz-Date'] = policy.datetime; req.fields['Policy'] = policy.encode(); req.fields['X-Amz-Signature'] = signature; try { final res = await req.send(); await for (var value in res.stream.transform(utf8.decoder)) { print(value); } } catch (e) { print(e.toString()); } } |
Please note that this method requires you to provide your Access Key and Secret Key. If you use a service like Cognito, it is recommended to get a temporary Access Key and Secret Key.
If you like this question & answer and want to contribute, then write your question & answer and email to freewebmentor[@]gmail.com. Your question and answer will appear on FreeWebMentor.com and help other developers.