2
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

aws-amplify-vueがカスタマイズできる件

本記事は CBCloud Advent Calendar 2020の17日目の投稿です。


環境

・Vue
・IDEA

目的

以前、aws-amplifyとaws-amplify-vueを使用して、ログイン機能を実装したのは良いものの、自分好みのフォームを作成したいなと思ったので、今回は、aws-amplify/ui-vueで再実装する。

1. emailとpasswardだけで認証できるように設定する
2. その後、routerでログイン済みユーザーだけが入れるようにする。

実装

はじめに

まず初めに、aws-amplifyとui-vueをインストールしましょう。

yarn add aws-amplify @aws-amplify/ui-vue
//or 
npm install aws-amplify @aws-amplify/ui-vue

amplifyの設定は、以前したものをそのまま使用しています。

以前amplifyを設定した時に参考にしたサイト
https://day-journal.com/memo/try-024/

構造

関係ありそうなやつだけ表示しています。

├── main.js
├── App.vue
├── router
│   ├── index.js
│   └── route.js
├── components
│   └── pages
│       └── Login.vue
└── store
    └── user.js

各種コード

main.js

@aws-amplify/ui-vueを入れます。

import Vue from 'vue'
import App from './App.vue'
import router from './router/index'
import store from './store/user'
import vuetify from './plugins/vuetify'

import '@aws-amplify/ui-vue'
import Amplify, * as AmplifyModules from 'aws-amplify'
import awsconfig from './aws-exports'
Amplify.configure(awsconfig)

Vue.use(AmplifyModules)

Vue.config.productionTip = false
Vue.prototype.$http = axios

new Vue({
  router,
  store,
  vuetify,
  render: h => h(App),
}).$mount('#app')

App.vue

自分はこのしたに、MainTemplateとSubTemplateを入れています。
MainTemplateは、主に認証が必要なページ、SubTemplateは、認証の必要がないページです。


<template>
  <div id="app">
    <v-app>
      <v-content>
        <router-view></router-view>
      </v-content>
    </v-app>
  </div>
</template>

<script>
export default {
  name: 'App',
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
</style>

router/index.js

今回の肝的な部分です。onAuthUIStateChangeで、AuthStateの変更を検知し、検知した場合に、storeに保管します。
お馴染みbeforeResolveで、認証が必要なページに入る前に、ログインしているかどうかチェックします。
認証がなかった場合には、loginページに飛ばします。

import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './route'

import store from '../store/user'

import AmplifyModules from 'aws-amplify'

import { AuthState, onAuthUIStateChange } from '@aws-amplify/ui-components'

Vue.use(VueRouter)
Vue.use(AmplifyModules)

onAuthUIStateChange((nextAuthState, authData) => {
  if (nextAuthState === AuthState.SignedIn) {
    store.commit('setUser', authData)
    router.push({ path: '/' })
  }
  if (!authData) {
    router.push({ path: '/login' })
    store.commit('setUser', null)
  }
})

let user

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
})

router.beforeResolve(async (to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    user = store.state.user
    if (!user) {
      return next({
        path: '/login',
      })
    }
    return next()
  }
  return next()
})

export default router

router/route.js

今回はMainとSubに別れていて、Mainに入る時には、

meta: { requireAuth: true }

認証を必要にしています。

export default [
  {
    name: 'MainTemplate',
    path: '/',
    component: () => import('../components/template/MainTemplate'),
    meta: { requiresAuth: true },
    children: [
     //なんか入ってる
    ],
  },
  {
    name: 'SubTemplate',
    path: '/',
    component: () => import('../components/template/SubTemplate'),
    children: [
      {
        name: 'Login',
        path: '/login',
        component: () => import('../components/pages/Login'),
      },
    ],
  },
]

components/pages/Login

Loginページです。username-aliasに"email"を入れることで、
->
こんな感じになります。
そして、sign-up時のカスタマイズは、formFieldsで設定できます。

<template>
  <div class="login">
    <amplify-authenticator username-alias="email">
      <amplify-sign-up
        slot="sign-up"
        username-alias="email"
        :form-fields.prop="formFields"
      ></amplify-sign-up>
      <amplify-sign-in slot="sign-in" username-alias="email"></amplify-sign-in>
    </amplify-authenticator>
  </div>
</template>

<script>
import { onAuthUIStateChange } from '@aws-amplify/ui-components'
export default {
  name: 'Login',
  data: () => ({
    user: undefined,
    authState: undefined,
    formFields: [
      {
        type: 'email',
        label: 'Custom email Label',
        placeholder: 'custom email placeholder',
        required: true,
      },
      {
        type: 'password',
        label: 'Custom Password Label',
        placeholder: 'custom password placeholder',
        required: true,
      },
    ],
  }),
  created() {
    onAuthUIStateChange((authState, authData) => {
      this.authState = authState
      this.user = authData
    })
  },
  beforeDestroy() {
    return onAuthUIStateChange
  },
}
</script>

store/user.js

普通のstoreです。


import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    user: null,
  },
  mutations: {
    // ユーザー情報保存
    setUser(state, user) {
      state.user = user
    }
  },
})

export default store

これで動くはずです。

後述

私が、先日実装したやつなのですが、もっと効率の良い実装方法はあるはずです。
もし何かあれば、教えていただけるとありがたいです。

参考文献

カスタマイズ前のコード -> https://day-journal.com/memo/try-024/
本家 -> https://docs.amplify.aws/ui/q/framework/vue
amplifyの環境構築 -> https://qiita.com/shunp/items/d491adfadd570f66f990

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
2
Help us understand the problem. What are the problem?