Vuejs、Cognito、AWS-Amplifyを使ってS3にサーバーレスな認証をつける
2018/11/07
Table of Contents
Cognitoユーザープールをつくる
まずはユーザープールをつくります。
今回は、
- ユーザー名
- パスワード
のみの認証で進めます。
パスワードの強度や、ユーザーへのサインアップの許可の選択
多要素認証や、メールアドレスの検証など、多くの機能が提供されています。
一点、注意点で、今回の開発はNode.jsを用いるのですが、その場合は上記の画面でアプリクライアントの作成をする際に
「クライアントシークレットを生成」
のチェックをはずす必要があります。
ユーザープール作成を終えると、IDが発行されます。
Cognitoフェデレーティッドアイデンティティを作る
続いてフェデレーティッドアイデンティティを作ります。
認証プロバイダーは先ほど作成したCognitoのIDを入力します。
認証したIAMRoleと
認証してないIAMRoleを作成し、フェデレーティッドアイデンティティの設定は完了です。
S3バケットを作成
使用するS3バケットを作成します。
今回はyoshino-cognitoというバケットをつくりました。
また、CORSの設定を以下のように変更します。
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<ExposeHeader>x-amz-server-side-encryption</ExposeHeader>
<ExposeHeader>x-amz-request-id</ExposeHeader>
<ExposeHeader>x-amz-id-2</ExposeHeader>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
IAMロールに対してS3バケットへのアクセス権限を付与する
次にAuthロールに対して、S3バケットへのアクセス権限を付与します。
IAMポリシーは以下の通りです。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"mobileanalytics:PutEvents",
"cognito-sync:*",
"cognito-identity:*"
],
"Resource": [
"\*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::yoshino-cognito/private/${cognito-identity.amazonaws.com:sub}",
"arn:aws:s3:::yoshino-cognito/private/${cognito-identity.amazonaws.com:sub}/*"
]
}
]
}
yoshino-cognitoというバケットの中の、CognitoログインしているユーザーのIDに対して、GetやPutができるような設定になっています。
サインアップ、サインイン機構をAWS-Amplifyで作る
Vue.jsで作っていきます。
$ vue init webpack sample
$ cd sample
$ yarn add aws-amplify
aws-amplifyの設定ファイルaws-exports.jsを作成します。
import Amplify from 'aws-amplify';
Amplify.configure({
Auth: {
// フェデレーションアイデンティティのID
identityPoolId: 'ap-northeast-1:自分のID',
// リージョン
region: 'ap-northeast-1',
// ユーザープールのID
userPoolId: 'ユーザープールのID',
// ユーザープールのウェブクライアントID
userPoolWebClientId: '',
mandatorySignIn: true,
},
Storage: {
bucket: 'yoshino-cognito', //使用するS3バケット名
region: 'ap-northeast-1', //リージョン
},
});
HelloWorld.vueを編集して、サインアップとログインができるようにします。
<template>
<div class="page">
<div class="login-form">
<p>ログイン</p>
<p>{{ status }}</p>
<p>{{ message_text }}</p>
<label>ユーザー名</label>
<input type="text" v-model="userInfo.username">
<label>パスワード</label>
<input type="password" v-model="userInfo.password">
<button class="btn btn-primary" @click="signIn()">ログイン</button>
<button class="btn btn-primary" @click="signOut()">ログアウト</button>
<button class="btn btn-primary" @click="put()">PUT</button>
<button class="btn btn-primary" @click="get()">GET</button>
<img :src=url>
</div>
<div class="login-form">
<p>サインアップ</p>
<label>ユーザー名</label>
<input type="text" v-model="userInfo.username"/>
<label>パスワード\</label>
<input type="password" v-model="userInfo.password">
<button class="btn btn-primary" @click="signUp()">サインアップ</button>
</div>
</div>
</template>
<script>
import Amplify, { Auth, Storage } from 'aws-amplify';
import aws_exports from '../../aws-exports';
Amplify.configure(aws_exports);
export default {
data () {
return {
status: '',
userInfo: {
username: '',
password: '',
},
message_text: '',
url: '',
};
},
created() {
Auth.currentSession()
.then((data) => {
this.status = 'ログインしています'
}).catch((err) => {
this.status = 'ログインしていません'
});
},
methods:{
put: function () {
Storage.put('test.txt', 'Hello', { level: 'private', contentType: 'text/plain'})
.then (result => console.log(result))
.catch(err => console.log(err))
},
get: function () {
Storage.configure({ level: 'private' });
Storage.get('bird.png')
.then ((result) => {
console.log(result)
this.url = result;
})
.catch(err => console.log(err));
},
signUp: function () {
Auth.signUp(this.userInfo.username, this.userInfo.password)
.then((data) => console.log(data))
.catch((err) => console.log(err));
},
signIn: function () {
Auth.signIn(this.userInfo.username, this.userInfo.password)
.then((data) => {
this.message_text = 'ログインしました';
this.status = 'こんにちは、'+data.username+'さん';
}).catch((err) => {
this.message_text = 'ログインできませんでした';
});
},
signOut: function () {
Auth.signOut()
.then((data) => {
this.message_text = 'ログアウトしました';
}).catch((err) => {
this.message_text = 'ログアウトできませんでした';
});
},
}
}
</script>
<style scoped>
.login-form {
margin: 20;
}
</style>
このような画面になります。
ユーザーを作成、ログインしてみる
まず、サインアップからユーザーを作成します。
サインアップに成功すると、トークンが発行されます。
ここでそのままログインしようとすると、
UserNotConfirmedExceptionというエラーが発生します。
ユーザーの確認ができていない、とのことなので、ユーザープールにアクセスします。
以下のようにユーザーが作成されているので、「ユーザーの確認」を押します。
再度ログインしてみると、ログインに成功します。
S3にオブジェクトをput,getしてみる
Putボタンを押すと、「text.txt」が指定したS3に保存されます。
S3を確認すると
保存されているのが確認できます。
パスは、privateファイルの設定の場合
バケット名/private/ユーザー固有のID/ファイル名
に自動的に設定してくれます。
では次にS3の同じ場所にbird.pngという画像ファイルを設置し、状態で、GETボタンを押すと
S3から画像を取得してくれます。
ユーザーごとの認証になっているか確認する
ここで一度ログアウトして、リロードした上で、画像の取得をしてみます。
「No Credential」という表示がでて、取得ができません。
また、他のユーザーでログインをしても、同じく取得ができません。
以上、Vuejs、Cognito、AWS-Amplifyを用いたS3上のファイルのユーザー認証でした。
こんなに簡単にユーザー認証と、ユーザーによるアクセス制限ができるのは、本当に便利です。
今後も使っていきたいと思いました!