これさえあればWEBアプリが簡単に作れる!Nuxt・Express・Vuetifyを使ったログイン画面の実装テンプレ

これさえあればWEBアプリが簡単に作れる!Nuxt・Express・Vuetifyを使ったログイン画面の実装テンプレ:


目的

nuxt.jsを使うことでWEBアプリが簡単に作れるようになりました。

加えてVuetifyやExpressを使うことで、高度なWEBアプリが開発できます。

今回はそれらを使ったログイン画面の実装テンプレートを紹介します。


実装に向けて

https://github.com/nuxt-community

基本このGithubを参考にしました。

Expressやauth-moduleのテンプレートはありますが、

まるっと統合したものが欲しかったので、これらを応用して作成しました。


使用したフレームワーク・ライブラリ

  • nuxt
  • Express(API)
  • vuetify(デザイン)
  • axios(API通信)


ドキュメント


GitHubレポジトリ

https://github.com/tonio0720/nuxt_login_template


ソース解説


フォルダ構成

./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)


login.PNG



最後に

いかがでしたでしょうか。

不明点等あれば、コメントにお願いいたします!

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)