コンテンツにスキップするには Enter キーを押してください

Vuejs、Cognito、AWS-Amplifyを使ってS3にサーバーレスな認証をつける

こんにちは、最近家でずっと楽器のマウスピースを吹いている吉野です。

AWSのCognitoはIAMを用いた認証や、その他のアカウントでの認証も簡単に実装することができます。
また、AWS-Amplifyは、AWS-SDKをそのまま使うよりも、モバイルに特化した機能を簡単な設定で使用することができます。

今回はそんな二つを使って、ServerlessでS3のバケットにユーザー認証機能をつけたいと思います。

  

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上のファイルのユーザー認証でした。

こんなに簡単にユーザー認証と、ユーザーによるアクセス制限ができるのは、本当に便利です。

今後も使っていきたいと思いました!

Fusicエンジニア。Webアプリケーションやブロックチェーンプログラミングをしています。PHP, Vue.js, Solidity etc..

コメントする

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です