使用Node.js + Express + MySQL + Passport创建简单的登录功能

首先

登录功能虽然非常基本,但从某种意义上来说也是非常重要的功能。
最近,我们不再将密码保存在自己的数据库中,而是可以使用Google或Facebook的ID来代替。因此,在个人运营的网站等方面,个人信息管理的重要性似乎有所降低。
在这里,我们将使用nodejs + express + mysql来编写登录功能和方法。

环境

Windows 10
MySQL 8.0.31
Express: 4.18.2

代码

MySQL是一种开源的关系型数据库管理系统。

image.png

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) 可以用以下方式进行近义词表达:嵌入动态HTML模板的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>

只配备了最基本的输入框和按钮。

登录

登录失败

image.png

成功登录

image.png

曲奇饼 (qǔ qí

image.png

登录后,可以看到生成了Cookie。这证明了登录状态,并且服务器可以从Cookie中获取当前用户信息的一部分。

image.png

登录后,从数据库中提取用户信息。通过这样可以在我的页面上显示个人信息,并且可以进行个人信息和密码的更改。

最后

这段代码虽然看起来很长且复杂,但实际上只是从数据库中提取与所输入的ID匹配的数据,并且如果密码也匹配,则登录成功;否则登录失败。然后将该ID的信息保存在Cookie中,在需要的时候从数据库中提取并使用。
其他功能都由库来完成。
虽然此次的介绍是基于mysql的,但是原理在其他数据库,如mongoDB等,也是相同的,因此可以使用passport库来实现登录功能。

广告
将在 10 秒后关闭
bannerAds