Nuxt.jsとAmazon Cognitoでユーザー登録、ログインを実装しました。
mode:'spa'
です。
リポジトリ: nuxt-aws-amplify-sample
実装にあたり以下の記事とリポジトリを大いに参考にしました。
Cognitoの準備
ユーザープール作成
基本的にはデフォルトのままです。1ヶ所だけ変えています。
「属性」の「エンドユーザーをどのようにサインインさせますか」を「Eメールアドレスおよび電話番号」「Eメールアドレスを許可」に変更します。
これにより、メールアドレスでログインできるようになります。
ユーザープールを作成すると、「プールID」が発行されます。
「アプリクライアント」を開きます。「クライアントシークレットを作成」のチェックを外し、作成してください。
作成すると、「アプリクライアントID」が発行されます。
IDプール作成
「認証されていないIDに対してアクセスを有効にする」にチェックを入れてください。
認証プロバイダーで「Cognito」を選び、「ユーザープールID」と「アプリクライアントID」に先ほど発行されたIDを登録します。
「IDプールの編集」画面に行くと、「IDプールのID(ややこしい)」がわかります。
これでCognitoの準備は終わりです。
追加ライブラリ
AWS Amplify
JavaScriptからAWSの機能を利用するためのライブラリ。
@nuxtjs/dotenv
Nuxtで.envを利用するためのライブラリ。
$ yarn add aws-amplify
$ yarn add @nuxtjs/dotenv
aws-amplifyの初期化
初期化はpluginで行なっています。
.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をしないと一瞬画面が表示されてしまいます。
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 () {
Auth.signUp(this.email, this.password)
.then(data => {
this.$store.dispatch('amplify/setUsername', this.email)
this.$router.push('/confirm')
})
.catch(err => this.errors = err)
}
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任せになってほしい。