Posted at

Nuxt.jsとaws-amplifyでログインするだけ

More than 1 year has passed since last update.

Nuxt.jsAmazon Cognitoでユーザー登録、ログインを実装しました。

mode:'spa'です。

リポジトリ: nuxt-aws-amplify-sample

実装にあたり以下の記事とリポジトリを大いに参考にしました。


Cognitoの準備


ユーザープール作成

基本的にはデフォルトのままです。1ヶ所だけ変えています。

「属性」の「エンドユーザーをどのようにサインインさせますか」を「Eメールアドレスおよび電話番号」「Eメールアドレスを許可」に変更します。

これにより、メールアドレスでログインできるようになります。

スクリーンショット 2018-06-14 15.36.53.png

ユーザープールを作成すると、「プールID」が発行されます。

「アプリクライアント」を開きます。「クライアントシークレットを作成」のチェックを外し、作成してください。

スクリーンショット 2018-06-14 15.38.45.png

作成すると、「アプリクライアントID」が発行されます。


IDプール作成

「認証されていないIDに対してアクセスを有効にする」にチェックを入れてください。

認証プロバイダーで「Cognito」を選び、「ユーザープールID」と「アプリクライアントID」に先ほど発行されたIDを登録します。

スクリーンショット 2018-06-14 15.44.26.png

「IDプールの編集」画面に行くと、「IDプールのID(ややこしい)」がわかります。

これでCognitoの準備は終わりです。


追加ライブラリ

AWS Amplify

JavaScriptからAWSの機能を利用するためのライブラリ。

@nuxtjs/dotenv

Nuxtで.envを利用するためのライブラリ。

$ yarn add aws-amplify

$ yarn add @nuxtjs/dotenv


aws-amplifyの初期化

初期化はpluginで行なっています。

.envファイルはコミットしていないので、ルートディレクトリに準備してください。


.env

AWS_AMPLIFY_AUTH_REGION=リージョン

AWS_AMPLIFY_AUTH_USER_POOL_ID=ユーザープールID
AWS_AMPLIFY_AUTH_USER_POOL_WEB_CLIENT_ID=アプリクライアントID
AWS_AMPLIFY_AUTH_IDENTITY_POOL_ID=IDプールのID

たぶんaws-exportsを使う方がいいのでしょうが、フォーマットがわからなかったもので……。


画面

ログインや登録処理は各vueファイルに記載しています。


  • index.vue: トップページ

  • secret.vue: ログイン時にしか見られないページ

  • signin.vue: ログインフォーム

  • signup.vue: 新規登録フォーム

  • confirm.vue: 認証フォーム


ログイン判定

参考記事の知見に従い、middlewareに実装しました。未ログインの場合、ログインフォームに遷移します。

async/awaitをしないと一瞬画面が表示されてしまいます。


amplify-auth.js

import { Auth } from 'aws-amplify'

export default async ({ redirect }) => {
let signed_in = false
await Auth.currentUserInfo()
.then(data => signed_in = Boolean(data))
.catch(err => console.log(err))
.then(() => signed_in || redirect('/signin'))
}


aws-amplify-vueでは、Auth.currentUserInfo()ではなく、Auth.currentAuthenticatedUser()をしてからAuth.currentCredentials()しています。

どちらの方がよいのでしょうか?

というか単純にログイン状態を見るようなことはできないのね。


登録後の認証

Cognitoに新規登録をすると、メールアドレスに認証コードが送られます。認証に必要なのはこのコードとusername(今回はメールアドレス)です。

何度も入力するのは手間なので、新規登録時にメールアドレスをstoreに保管し、認証フォームではstoreに値があれば最初から入力されている状態になるようにしました。


signup.vue

signUp () {

Auth.signUp(this.email, this.password)
.then(data => {
this.$store.dispatch('amplify/setUsername', this.email)
this.$router.push('/confirm')
})
.catch(err => this.errors = err)
}


confirm.vue

data () {

return {
email: this.$store.getters['amplify/username'],
code: '',
errors: ''
}
},

aws-amplify-reactでは、storeにusernameがあればformにhiddenを追加し、なければ入力欄を表示するような作りになっています。


その他

プロダクションレベルにするためには、まだまだ考慮しなければいけないことが多そう。


エラー処理

入力値のバリデーションはaws-amplifyでやってくれます。

バリデーションエラーを含めたエラーメッセージは日本語化されないため、独自に設定する必要がありそうです。


パスワード変更必須

Cognito側でユーザーを作成すると仮パスワードが発行され、パスワード変更必須状態になります。

ログイン時にユーザーの状態を確認し、パスワード変更画面に遷移させる必要があるでしょう。


SSR

aws-amplifyはlocalStorageを使っているため、SSRするとログイン判定が行えません。

参考記事ではCookieを利用しています。

そもそもログイン機能が必要な画面でSSRする必要があるのか、という疑問……。


IAM

Cognitoが行うのはユーザーの認証だけで、リソースへのアクセス許可はIAMで行います。

IDプールで認証されたユーザーに与えられるロールが決められるので、適切に設定する必要があります。

(この辺りがややこしくて現状は「あーそーゆことね完全に理解した」状態)


それはともかく

慣れるとPHPとMySQLでゴニョゴニョするよりはるかに楽です。

もうユーザー関連は全部Cognito任せになってほしい。