本記事は 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