AmplifyのStorageと認証まわり
はじめに
サーバーレスWebアプリ開発を進めてくなかで、AmplifyのStorageと認証まわりの理解が進んできて、完全に理解したなと思ってJAWS-UG浜松で発表しようとしたら全然できませんでした。
できなかったというか、話し始めようとしたら話せるほど自分のなかで整理できてないことに気付いてギブアップしました。発表内容はこれだけじゃなかったとはいえ、まぁ失礼な話ですよね。本当すみません。
リベンジすべく、整理するために記事を書きます。
Guest許可と認証ユーザーのみ
AmplifyのStorageをセットアップする際の質問のなかに以下のような質問があって、選択できます。
? Who should have access: (Use arrow keys)
Auth users only
Auth and guest users
- Auth user only
Storageへアクセスするためにユーザー認証(ログイン)が必要。 - Auth and guest users
ユーザー認証していない状態でもStorageへアクセスできる。
ファイルアップロード(put)
Amplifyを利用してファイルをS3にアップロードするJavaScriptのコード例
:
import { Storage } from 'aws-amplify';
:
Storage.put(filePath, image).then(result => {
console.log(result);
}).catch(err => console.log(err));
例えばfilePath = "a/b/c/test.jpg"
とした場合、
resultには key : a/b/c/test.jpg
のような結果(要はS3 Object key)が返ってきます。
そしてバケットには以下のようにpublic/a/b/c/test.jpg
としてファイルがアップロードされます。
public
が先頭についてますが、これはアクセスレベルです。
AmplifyのStorageには3つのアクセスレベルがあります。
- public : 全員が読み書きできる。
- protected : 全員が読めるが、書けるのは自分だけ。
- private : 自分しか読み書きできない。
protectedの場合は以下のように書きます。
Storage.put(filePath, image, {
level: 'protected'
}).then(result => {
console.log(result);
}).catch(err => console.log(err));
privateの場合は、protectedをprivateにすればいいだけです。
protectedやprivateの場合、アップロードされるパスの先頭には、アクセスレベルに続きCognito Identity ID
が付きます。
なお、Guestでprotectedやprivate指定した場合、以下の例外とともに HTTP403(Forbidden(閲覧禁止))が返ってきました。
AWSS3Provider - error uploading AccessDenied: Access Denied
ファイルダウンロード(アドレス取得)(get)
Amplifyを利用してS3にあるファイルの参照URLを取得するJavaScriptのコード例
Storage.get(s3key).then(result => {
this.imageURL = result;
}).catch(err => console.log(err));
s3key = "a/b/c/test.jpg"
このように、s3keyにはアクセスレベル名やCognito Identity IDを付けないことに注意。
resultに以下のようなURLが取得できます。
https://sample-vue-project-bucket-work.s3.ap-northeast-1.amazonaws.com/public/a/b/c/test.jpg?X-Amz-Algorithm=xxx&X-Amz-Credential=xxx&X-Amz-Date=xxx&X-Amz-Expires=900&X-Amz-Security-Token=xxx&X-Amz-Signature=xxx&X-Amz-SignedHeaders=host
後ろに認証のための色々なパラメータが付いてますね。これがないとアクセスが拒否されます。
また、デフォルトで900秒(15分)という有効期限も付いています。
任意の有効期限を指定することもできます。
let s3key = "a/b/c/test.jpg"
let dataExpireSeconds = (30 * 60);
Storage.get(s3key, { expires: dataExpireSeconds }).then(result => {
this.imageURL = result;
}).catch(err => console.log(err));
適切な認証パラメータではなかったり、有効期限が切れた後にgetすると、HTTP403(Forbidden(閲覧禁止))とともにエラーが返ってきます。
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>D43YC2E5080A822C</RequestId>
<HostId>
w7zzd5NRpm8Ih0DN3hmjZT8sDQT5hcV7FhqbUaW6ZG7SpsepV3UspzDUMDVKRkPesaUpyUSEGC0=
</HostId>
</Error>
<Error>
<Code>AccessDenied</Code>
<Message>Request has expired</Message>
<X-Amz-Expires>900</X-Amz-Expires>
<Expires>2020-01-26T03:07:16Z</Expires>
<ServerTime>2020-01-26T03:20:13Z</ServerTime>
<RequestId>9F14A2CA61AE75F2</RequestId>
<HostId>
wru7usdhgiI2MXWsdFGh59x8JYl1TbOzPDMs2L5LZ/IwDD9tueInxK7bfh/rKftjJZCCf9CY7SE=
</HostId>
</Error>
AmplifyのAuthによる認証
ゲストを許可した場合は不要ですが、そうではない場合は認証をパスした状態でputやgetをする必要があります。
ユーザーにサインインしてもらう
Amplifyを利用した一般的な実現方法としては、AmplifyのAuthの基本機能を利用して、ユーザーにアカウントを作ってもらったうえでサインインしてもらう形になるかと思います。
こんな感じの画面でユーザー登録や認証の基盤を構築することがサクッと実現できちゃいます。
AmplifyでAuthをセットアップをする手順などの詳細は、この記事では割愛します。
プログラムで自動的に認証する
ユーザーがログインしなくてもサービスを利用できるようにしたい場合、一般的にはゲストを許可する設定でセットアップして、ゲストとして処理してあげればいいと思います。
ただ、あえてゲストは利用せず、サービス側が予め用意したアカウントで自動的(ユーザーに意識させず)に認証をパスするということもできます。
細かな手順などはこちらの記事に書いてありますので、やはりこの記事では割愛します。
Cognitoユーザーを作成したうえで、JavaScriptで自動的にログインをします。
あとがき
まずは何か動くものを作る。座学よりも効率的に学ぶことができると思っています。
それを人に説明しようとした場合、やはりある程度は整理してまとめるという作業が必要になってきますね。改めて実感しました。
これからはちゃんと準備してから話をしようと思います。
さて今回はStorage観点での認証の話でしたが、次は認証そのもの、その中でも特にソーシャルログインについて学びたいと考えています。
アカウント作成って心理的ハードルが高く、また、手間がかかると思っていて、とはいえユーザー毎の情報を保護することも必要だと思ってます。
多少でも心理的ハードルを下げ、また、ユーザー認証の手間を少なくしてくれるソーシャルログインは、サービスにとって必須の機能ではないでしょうか。と、思うわけなんです。