LoginSignup
4
2

More than 1 year has passed since last update.

nodejs + express + mysql + passport を用いて簡単なログイン機能

Last updated at Posted at 2022-11-29

はじめに

ログイン機能はとても基本的な内容であるが、ある意味ともて大事な機能である。
最近は自分のデータベースにパスワードを保存せず、GoogleやFacebookのIDを代わりに利用できるので、
ユーザーの個人情報管理の重要さは、個人が運営するサイトなどにおいては減っている気がする。
ここではnodejs + express + mysqlを用いてログイン機能、方法を書く。

環境

window 10
mysql 8.0.31
express: 4.18.2

Code

Mysql

image.png
DBeaverからmysqlのaccountsのテーブルにこのようにユーザーの個人情報と、id, passwordを入れた。
ここでuser_idは固有の識別番号として設定した。

Nodejs

passport install
 npm install passport passport-local express-session
server.js
const express = require('express');
const mysql = require('mysql');
const app = express();
const bodyParser = require('body-parser');

require('dotenv').config()
app.use(bodyParser.urlencoded({ extended: true }));
app.set('view engine', 'ejs')
app.use('/public', express.static('public'))



// mysqlに接続
const con = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: process.env.MYSQL_PASSWORD,
    database: 'nodejs',
    dateStrings: "date",
    multipleStatements: true
});

// 他のファイルでmysqlを使えるようにexportします
module.exports = con

con.connect((err) => {
    if (err) {
        console.log('error connecting: ' + err.stack);
        return;
    }
});

// ここでlogin関連のapiを管理
app.use('/', require('./routes/login.js'));

app.listen(8080, function () {
    console.log('listening on 8080')
});

login.js
var router = require('express').Router();

// mysql
const con = require('./../server.js')

// loginを管理できるライブラリー
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');

router.use(session({ secret: '1234', resave: true, saveUninitialized: false }));
router.use(passport.initialize());
router.use(passport.session());

// loginページ
router.get('/login', function (req, res) {
    res.render('login.ejs')
});

// login
// loginに失敗した場合、/failに飛ばす
router.post('/login', passport.authenticate('local', { failureRedirect: '/fail' }), function (req, res) {
    res.redirect('/')
});

passport.use(new LocalStrategy({
    // id, pw のそれぞれのinputのnameと合わせる
    usernameField: 'id',
    passwordField: 'pw',
    session: true,
    passReqToCallback: false,
}, function (input_id, input_pw, done) {
    const sql = `select * from accounts where id = '${input_id}'`
    con.query(sql, function (err, result) {

        // mysql から取り出したaccounts情報から1番目の情報と照合する
        // 実際はもっとちゃんとした方がいいですが、なるべくシンプルに
        login_data = result[0]
        if (err) return done(err)
        if (!login_data) return done(null, false, { message: 'account does not exist' })
        if (input_pw == login_data.pw) {
            return done(null, login_data)
        } else {
            return done(null, false, { message: 'wrong password' })
        }
    })
}));

// ログインに成功したらuser.idのセッションを生成し、Cookieを作る
passport.serializeUser(function (user, done) {
    done(null, user.id)
});

passport.deserializeUser(function (user_id_saved, done) {
    // ユーザーの情報をDBから探す
    const sql = `select * from accounts where id = '${user_id_saved}'`
    con.query(sql, function (err, result) {
        done(null, result[0])
    })
});


// ミドルウェアでログイン有無によるページ接近の管理
function is_login(req, res, next) {
    if (req.user) {
        // loginした状態なら、通す
        next()
    } else {
        // loginしてないならこのページに飛ばす
        res.render('login.ejs')
    }
}

// ミドルウェアでログインしているかチェックし、ログインしているならreq.userのDBを見せる
router.get('/mypage', is_login, function (req, res) {
    // deserializeUserで得られたuserのDBデータ持ってくる
    console.log(req.user)
    res.send(req.user)
})



module.exports = router;

ejs(html)

login.ejs
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"
    integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"
    crossorigin="anonymous"
  /> 
    <title>Document</title>
  </head>
  <body>
    <div class="container mt-4">
      <form action="/login" method="POST">
        <div class="form-group">
          <label>id</label>
          <input type="text" class="form-control" name="id" />
        </div>
        <div class="form-group">
          <label>pw</label>
          <input type="text" class="form-control" name="pw" />
        </div>
        <button type="submit" class="btn btn-danger">login</button>
      </form>
    </div>
  </body>
</html>

最低限のinputbuttonだけ備えた。

ログイン

ログイン失敗

image.png
ログインに失敗したとき、先ほど設定した/failに飛ばされる。
このページは別で設定した404ページ

ログイン成功

image.png

Cookie

image.png

ログインした後、Cookieが生成されたことがわかる。これによってログインしている状態であることが証明され、サーバーは現在のuser情報の一部をCookieから得ることができる。

image.png

ログイン後、DBからユーザー情報を取り出した。
これによってマイページで自分の情報を見せ、個人情報を変更したり、パスワードを変更したりすることができる。

おわりに

コードが長くて難しいように見えるが、データベースから入力したid と一致するデータを取り出し、pwも一致ならログイン、それ以外なら失敗するだけのコードです。そしてそのidの情報をCookieに保存し、必要なときはDBからその都度、取り出して用いる。
あとの機能はすべてライブラリーの力にお任せです。
今回はmysqlで紹介しましたが、mongoDBのように、他のDBでも原理は一緒なのでpassportでログイン機能を作ることができます。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2