目的
nuxt.jsを使うことでWEBアプリが簡単に作れるようになりました。
加えてVuetifyやExpressを使うことで、高度なWEBアプリが開発できます。
今回はそれらを使ったログイン画面の実装テンプレートを紹介します。
実装に向けて
https://github.com/nuxt-community
基本このGithubを参考にしました。
Expressやauth-moduleのテンプレートはありますが、
まるっと統合したものが欲しかったので、これらを応用して作成しました。
使用したフレームワーク・ライブラリ
- nuxt
- Express(API)
- vuetify(デザイン)
- axios(API通信)
ドキュメント
GitHubレポジトリ
ソース解説
フォルダ構成
./api # Express
./api/index.js
./api/routes # Express Router
./api/routes/auth.js # 認証用API
./assets
./assets/css
./assets/css/main.css # 全体のCSS
./components
./layouts # レイアウト
./layouts/default.vue # デフォルトのレイアウト(Vuetify)
./layouts/error.vue
./layouts/blank.vue # ログイン画面用のレイアウト(ログイン画面ではヘッダーとかは見えてほしくないので)
./nuxt.config.js # nuxtの設定
./package.json
./pages # この中に各ページを作る
./pages/index.vue # ホーム画面
./pages/login.vue # ログイン画面
./plugins
./static
./static/favicon.ico
./store
./store/index.js
nuxt.config.js
nuxt.config.js}
module.exports = {
// <head>タグの中身
head: {
title: 'nuxt-login-template',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: 'nuxt login template' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{
rel: 'stylesheet',
type: 'text/css',
href: 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'
}
]
},
plugins: [],
css: [
// 全体のCSS
'~/assets/css/main.css'
],
build: {
vendor: ['@nuxtjs/axios'],
extractCSS: true,
extend(config) {
if (process.server && process.browser) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
});
}
}
},
serverMiddleware: [
// API
'~/api/index.js'
],
// ライブラリの読込
modules: [
'@nuxtjs/axios',
'@nuxtjs/auth',
'@nuxtjs/vuetify'
],
axios: {
proxy: true
},
proxy: {
'/api': `http://${process.env.HOST || 'localhost'}:${process.env.PORT || 3000}`
},
// ここでauth-moduleを有効にする
auth: {
redirect: {
login: '/login',
logout: '/',
callback: '/login',
home: '/'
},
strategies: {
local: {
endpoints: {
login: {
url: '/api/auth/login',
method: 'post',
propertyName: 'token.accessToken'
}
}
}
}
},
// Vuetifyを有効にする
vuetify: {}
};
api
Expressを使って実装。
認証はexpress-jwtを使用。
index.js
index.js}
const express = require('express');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const jwt = require('express-jwt');
const app = express();
const secret = 'dummy'; // jwt secret
app.use(cookieParser());
app.use(bodyParser.json());
// ログインしてなくてもここにはアクセスできる
app.use(
jwt({ secret })
.unless({ path: '/api/auth/login' })
);
app.use('/auth', require('./routes/auth'));
// other routes
app.use((err, req, res, next) => {
console.error(err);
res.status(401).send(err + '');
});
module.exports = {
path: '/api',
handler: app
};
routes/auth.js
auth.js}
const { Router } = require('express');
const jsonwebtoken = require('jsonwebtoken');
const router = Router();
const secret = 'dummy';
async function checkAuth({ username, password }) {
// ここでDBに接続するなり、IDPASSの確認
if (username === 'xxx' && password === 'xxx') {
return true;
}
return false;
}
router.post('/login', async (req, res, next) => {
const { username, password } = req.body;
if (!await checkAuth({ username, password })) {
res.status(401).send('Invalid username or password');
return;
}
const accessToken = jsonwebtoken.sign({
username
}, secret);
res.json({ token: { accessToken } });
});
router.get('/user', (req, res, next) => {
res.json({ user: req.user });
});
router.post('/logout', (req, res, next) => {
res.json({ status: 'OK' });
});
module.exports = router;
pages
index.vue
index.vue}
<template>
<v-container fluid>
index
</v-container>
</template>
<script>
export default {
// middlewareにauthを追加することで、
// ログインしていないとログイン画面にリダイレクトされる
middleware: ['auth'],
head() {
return {
title: 'ホーム'
};
}
};
</script>
<style scoped>
</style>
login.vue
login.vue}
<template>
<v-container>
<v-layout justify-center>
<v-flex xs12 sm4>
<v-toolbar color="primary" dark>
<v-toolbar-title>ログイン</v-toolbar-title>
</v-toolbar>
<v-card>
<v-container fluid>
<v-form ref="form" v-model="valid" lazy-validation>
<v-layout row wrap>
<v-flex xs12>
<v-alert v-if="error" :value="true" type="error" outline>
{{ error }}
</v-alert>
</v-flex>
</v-layout>
<v-layout row wrap>
<v-text-field type="text" v-model="username" label="ログイン名" required></v-text-field>
</v-layout>
<v-layout row wrap>
<v-text-field type="password" v-model="password" label="パスワード" required></v-text-field>
</v-layout>
<v-layout row wrap justify-end>
<v-btn color="success" :disabled="!valid" @click="login">ログイン</v-btn>
</v-layout>
</v-form>
</v-container>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>
<style scoped>
</style>
<script>
export default {
layout: 'blank', // layouts/blank.vueを使用
middleware: ['auth'],
head() {
return {
title: 'ログイン'
}
},
data() {
return {
valid: true,
username: '',
password: '',
error: null
};
},
methods: {
async login() {
this.error = null;
if (this.$refs.form.validate()) {
return this.$auth
.loginWith('local', {
data: {
username: this.username,
password: this.password
}
})
.catch(e => {
this.error = 'ログインに失敗しました。IDかパスワードが間違っている可能性があります。';
});
}
}
}
}
</script>
使い方
ソースのダウンロード
$ git clone git://github.com/tonio0720/nuxt_login_template.git .
依存のインストール
$ npm i
開発環境に実装
$ npm run dev
※username:xxx、password:xxxでログインできます。(api/routes/auth.js)
最後に
いかがでしたでしょうか。
不明点等あれば、コメントにお願いいたします!