はじめに
ログイン機能はとても基本的な内容であるが、ある意味ともて大事な機能である。
最近は自分のデータベースにパスワードを保存せず、GoogleやFacebookのIDを代わりに利用できるので、
ユーザーの個人情報管理の重要さは、個人が運営するサイトなどにおいては減っている気がする。
ここではnodejs + express + mysqlを用いてログイン機能、方法を書く。
環境
window 10
mysql 8.0.31
express: 4.18.2
Code
Mysql
DBeaverからmysqlのaccountsのテーブルにこのようにユーザーの個人情報と、id, passwordを入れた。
ここでuser_idは固有の識別番号として設定した。
Nodejs
npm install passport passport-local express-session
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')
});
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)
<!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>
最低限のinput
とbutton
だけ備えた。
ログイン
ログイン失敗
ログインに失敗したとき、先ほど設定した/fail
に飛ばされる。
このページは別で設定した404ページ
ログイン成功
Cookie
ログインした後、Cookieが生成されたことがわかる。これによってログインしている状態であることが証明され、サーバーは現在のuser情報の一部をCookieから得ることができる。
ログイン後、DBからユーザー情報を取り出した。
これによってマイページで自分の情報を見せ、個人情報を変更したり、パスワードを変更したりすることができる。
おわりに
コードが長くて難しいように見えるが、データベースから入力したid と一致するデータを取り出し、pwも一致ならログイン、それ以外なら失敗するだけのコードです。そしてそのidの情報をCookieに保存し、必要なときはDBからその都度、取り出して用いる。
あとの機能はすべてライブラリーの力にお任せです。
今回はmysqlで紹介しましたが、mongoDBのように、他のDBでも原理は一緒なのでpassportでログイン機能を作ることができます。