12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ハンズラボAdvent Calendar 2021

Day 22

フロントエンドエンジニアに贈る、爆速Amplifyのすゝめ

Last updated at Posted at 2021-12-21

この記事は ハンズラボ Advent Calendar 2021 22日目の記事です。

amplify.png
バックエンドさんがAWS cognitoの環境構築をしてくれたなら、
我々フロントエンドは10分でログイン/ログアウトを実装できます。そう、Amplifyならね。

というわけで、この記事では既存AWSリソースがある場合の
・ログイン/ログアウト
・REST API呼び出し
・S3読み書き
を、爆速実装する方法を紹介します。

Amplify使い始めて2年が経とうとしていますが、社内にあまり浸透していないので
「これを読めばだいたい使いこなせるようになるぞ!」という記事を目指して書けたらと思います。
簡単さも伝わればいいな。

良い子のみんなは気づいたと思いますがVue.jsでやります(が、Vue.js以外でも応用できると思います)。

VueCLIを使うよ

言い忘れましたがVue.jsをそこそこ触っている人に向けて書きますので、細かい説明は省きます。

VueCLIで作成したプロジェクトでAmplifyを使います。
バージョンはVueは2系、CLIは3〜4で動くと思います。

bash
$ vue create sample-project

ログイン・ログアウトを実装するよ

カンタン3ステップ

  1. VueプロジェクトにAmplifyをインストール
  2. 設定
  3. ログイン・ログアウト処理のコーディング

1. VueプロジェクトにAmplifyをインストール

  • プロジェクトフォルダで以下コマンドを実行
bash
$ npm install aws-amplify
または
$ yarn add aws-amplify

2. 設定

  • envファイルに既存cognitoリソースの情報を記載
.env
VUE_APP_REGION='ap-northeast-1' // 東京リージョンの場合
VUE_APP_USER_POOL_ID='ユーザープールID'
VUE_APP_USER_POOL_WEB_CLIENT_ID='ウェブクライアントID'
VUE_APP_IDENTITY_POOL_ID='フェデレーションアイデンティティID'

フェデレーションアイデンティティIDはIDプールを使用している場合のみ必要です。

(参考までに)既存cognitoリソースの情報を調べる方法
  • ユーザープールID

    • ユーザープール > 全般設定 > プールID
      1.jpg
  • ウェブクライアントID

    • ユーザープール > アプリクライアント > アプリクライアントID
      2.jpg
  • フェデレーションアイデンティティID

    • フェデレーティッドアイデンティティ > サンプルコード > AWS認証情報の取得
      3.jpg
  • /src 下のどこかに構成ファイルを配置
bash
$ touch aws-exports.js
aws-exports.js
import Amplify from 'aws-amplify'

Amplify.configure({
  Auth: {
    // リージョン
    region: process.env.VUE_APP_REGION,
    // ユーザープールのID
    userPoolId: process.env.VUE_APP_USER_POOL_ID,
    // ユーザープールのウェブクライアントID
    userPoolWebClientId: process.env.VUE_APP_USER_POOL_WEB_CLIENT_ID,
    // フェデレーションアイデンティティのID
    identityPoolId: process.env.VUE_APP_IDENTITY_POOL_ID,
    // AWSリソースにアクセスする前にユーザー認証を行うかどうか
    mandatorySignIn: true
  },
})

  • main.jsで構成ファイルをインポート&ロード
main.js
import Amplify, { Auth } from 'aws-amplify';
import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

3. ログイン・ログアウト処理のコーディング

公式ドキュメント:Sign up, Sign in & Sign out

3-1. ログイン

  • サンプルで簡単なログイン画面を作ります
App.vue
<template>
  <div>
    <input v-model="id" placeholder="ID"/>
    <input v-model="password" placeholder="PASSWORD"/>
    <button @click="login()">login</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      id: "",
      password: "",
    };
  },
  methods: {
    login() {}
  },
}
</script>
  • Amplifyの認証ライブラリをインポートします
App.vue
<script>
import { Auth } from 'aws-amplify';

export default {...
  • ログインボタンクリック時のイベントでsignIn関数を使います

第一引数にユーザーid、第二引数にパスワードを渡してログインします。
ユーザーidは、メールアドレスだったりユーザーネームだったりcognito側の設定に合わせます。

App.vue
<script>
...
  methods: {
    async login() {
      try {
        const user = await Auth.signIn(this.id, this.password)
        console.log(user);
      } catch (error) {
        console.log('error signing in', error);
      }
    }
  }

コンソールログにユーザー情報が表示されていればログイン完了です!(ちなみにレスポンスとしてユーザー情報に何を載せるかはcognito側の設定で変えられます)
エラーだった場合、エラーコードを確認すると原因がわかります。

App.vue
<script>
...
} catch (error) {
  if(error.code === 'NotAuthorizedException') {
    alert('パスワードが誤っています');
  } else if(error.code === 'UserNotFoundException') {
    alert('ユーザーIDは存在しません');
  } else {
    alert('ログインに失敗しました')
  }
}

エラーコード一覧が公式ドキュメントで見つかりませんでした…orz
こちらの記事が参考になると思います:Cognito のエラーコードまとめ

3-2. ログアウト

  • ログアウトボタンクリック時のイベントでsignOut関数を使います
Auth.signOut()

3-3. (おまけ)よく使う認証系関数

currentAuthenticatedUser

Auth.currentAuthenticatedUser()

認証情報を返します。
認証されていない・セッション期限切れの場合、エラーを返します。
→ログイン画面で認証済みかどうか確認し、認証済みだったらログイン処理を飛ばしてトップ画面にリダイレクトさせる、ということができる

changePassword

Auth.changePassword(user, 'oldPassword', 'newPassword');

パスワード変更用の関数です。
第一引数のuserは、前述したcurrentAuthenticatedUser関数で取得した認証情報になります。

他にもカスタムオーソライザーを使った二段階認証なども簡単に実装できるぞ!
https://docs.amplify.aws/lib/auth/switch-auth/q/platform/js/#customauth-flow

REST API呼び出しを実装するよ

公式ドキュメント:API(REST)

前項で認証したcognitoユーザーが呼び出すという前提でご紹介します。

  1. 設定
  2. API呼び出し処理のコーディング

1. 設定

  • さっき作ったaws-exports.jsを編集します
aws-exports.js
import Amplify from 'aws-amplify'

Amplify.configure({
  Auth: {
    ...
  },
  API: {
    endpoints: [
      {
        name: process.env.VUE_APP_API_NAME,
        endpoint: process.env.VUE_APP_API_ENDPOINT
      }
    ]
  }
})

API名とエンドポイントのURLをenvファイルに追加しておいてください。
API名はなんでもいいです。あとでAPI実行時に使います。

2. API呼び出し処理のコーディング

  • 設定のインポート
import { Auth, API } from 'aws-amplify'
const API_NAME = process.env.VUE_APP_API_NAME
  • getしてみる
const token = (Auth.currentSession()).getIdToken().getJwtToken()
const response = API
  .get(API_NAME, `/users`, {
    headers: {Authorization: token}
  })

.get()の第一引数にAPI名を入れることで、おそらくエンドポイントを参照してます。
第二引数はエンドポイントより後のパス、
第三引数のヘッダーに(Auth.currentSession()).getIdToken().getJwtToken()で取得したtokenを入れます。

以上でデータの受け取りができました。ね?簡単でしょ??
簡単さが伝われば良いので今回はここまでにしておきます。updateやdeleteの処理にも興味があれば公式ドキュメントを読んでみてください。
また、APIの作りによっても実装方法が変わる可能性がありますので、バックエンドの人と相談してみてください。

もしAccess to XMLHttpRequest at 'https://...' has been blocked by CORS policy というエラーメッセージが出たら、ユーザーにAPIを叩く権限がない可能性が高いです。

S3読み書きを実装するよ

公式ドキュメント:Storage - Using a Custom Plugin

前々項で認証したcognitoユーザーが読み書きするという前提でご紹介します。
classとかいう苦手概念が出てくるのであまり説明できませんが、コピペでできるように書きます。

  1. S3アップロード処理のコーディング
  2. 画面からアップロード
  3. S3ダウンロード処理のコーディング
  4. 画面からダウンロード

1. S3アップロード処理のコーディング

ドキュメント:Upload files

  • 別ファイルに書きましょう。/src 下のどこかにファイルを配置
bash
$ touch storage-service.js
  • 最初にStorageライブラリをインポートします
storage-service.js
import { Storage } from 'aws-amplify'
  • classを作成し、中に処理を書きます

ファイルを特定のバケットにアップロードする処理を書いてみます。

storage-service.js
export default class StorageService {
  constructor() {}
  static putFile(file_name, file) {
    Storage.configure({
      AWSS3: {
        bucket: process.env.VUE_APP_FILE_PUT_BUCKET,  // アップロード先のバケットを指定
        region: process.env.VUE_APP_REGION,           // バケットのあるリージョンを指定
      },
      level: 'public'                    // バケットのアクセスレベル。publicはデフォルト
    })
    return (
      Storage.put(file_name, file, {     // 第一引数:S3に置く時のオブジェクト名 第二引数:置くファイル
        progressCallback(progress) {
          console.log(`Uploaded: ${progress.loaded}/${progress.total}`) // opt.アップロード進行度
        },
      })
        .then (result => console.log(result))
        .catch(err => console.log(err))
    )
  }
}

Storage.configureで操作したいバケットの情報を設定します。
Storage.putでファイルをアップロードしています。

2. 画面からアップロード

  • inputでfileをv-modelし、ボタンなどのトリガーでファイルをアップロードします
App.vue
<script>
import StorageService from '@/storage-service.js'

export default {
  data() {
    return {
      file: null,
    }
  },
  methods: {
    upload() {
      StorageService.putFile(this.file.name, this.file) // 第一引数にファイル名、第二引数にファイル
    }
  },
}
</script>

まず、さきほど作ったclassをインポートします。
StorageService.putFileを呼び、アップロード処理を実行します。
指定したバケットにファイルが配置されていれば成功です。

3. S3ダウンロード処理のコーディング

次にダウンロードも書いていきます。
ドキュメント:Download files

  • 先ほど作ったclassに追加していきます
storage-service.js
export default class StorageService {
  constructor() {}
  static putFile(file_name, file) {
    ...
  },

  static getFile(file_name) {
    Storage.configure({
      AWSS3: {
        bucket: process.env.VUE_APP_FILE_GET_BUCKET,  // アップロード先のバケットを指定
        region: process.env.VUE_APP_REGION,           // バケットのあるリージョンを指定
      },
      level: 'public'                    // バケットのアクセスレベル。publicはデフォルト
    })
    return (
      Storage.get(file_name)             // 第一引数:ダウンロードしたいオブジェクトの名前
        .then ((result) => { return result })
        .catch(err => console.log(err))
    )
  }
}

アップロードの時と同じくバケット情報を設定後、Storage.getを使います。
レスポンスはデフォルトで署名付きURLになります。

4. 画面からダウンロード

App.vue
<script>
import StorageService from '@/storage-service.js'

export default {
  methods: {
    download() {
      location.href = StorageService.getFile('ファイル名')
    }
  },
}
</script>

classをインポートし、StorageService.getFileで署名付きURLを取得して画面からダウンロードさせます。
署名付きURLは期限があるので、ダウンロードボタンが押されるたびに取得するのがいいかと思います。

ダウンロードできない場合、以下のことを確認してみてください。(私がハマったポイントです)

  • ファイル名の文字コードがバケット上のファイルと同じか?
  • バケット上のファイルのメタデータ:Content-Typeがbinary/octet-streamになっているか?

image.png

また、APIと同じくAccess to XMLHttpRequest at 'https://...' has been blocked by CORS policy というエラーメッセージが出たら、ユーザーにAPIを叩く権限がない可能性が高いです。

まとめ

爆速実装できましたでしょうか?
Amplifyの公式ドキュメント、最初は英語が嫌でウワーーーーッとなっていましたが
chromeの日本語翻訳でも十分読めるし、わりと読みやすく書かれているので一番参考になりました。

読んでいただきありがとうございました!
明日の記事もお楽しみに:xmas-tree:

12
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?