daikiojm’s diary

ブログを書くときがやってきたどん!

connect-mongoをサクッと試す

社内勉強会で「Node.jsを使って社内で使える便利ツールを作ろう」というテーマで簡単なWebアプリケーションの作成を行っている。

Express+MongoDB+ejs(ほぼjQuery)で最低限の機能を実装したモノは出来上がったものの、ユーザー認証機能が未実装のままだったので、ちょっと残念な感じになっていた。

Express ユーザー認証とかで検索すると、Passportというパッケージを使うのが定跡なように感じたが、あまり頑張らずにサクッとユーザー認証機能を実装したかったので、今回はconnect-mongoというパッケージをサクッと試してみることにした。

Expressで認証を設定するプロジェクトの雛形を作成する

事前にexpress-generatorのインストールをしてある前提で、プロジェクトの雛形を作成し、動作確認を行います。 テンプレートエンジンにはejsを使用した。

$ mkdir connect-mongo-skt && cd connect-mongo-skt
$ express -e .
$ npm install
$ npm start

今回想定するログインのシナリオは、以下の通りです。

未ログイン時
* ルートへのアクセス
↓(リダイレクト)
* ログイン画面
↓(ログイン)
* ユーザーページ

ログイン時
* ルートへのアクセス
↓(リダイレクト)
* ユーザーページ

ユーザー認証に成功すると、ユーザーページへアクセス可能になるという動作に必要なrouterとviewの作成を行います。 express-generatorで作成した雛形には以下のように、indexとusersページが作成されているので、

  • index → ログイン画面
  • users → ログイン認証に成功されたら表示する画面

追加で、以下のviewを作成しました。(コードは後述)

  • login → ログイン前にindexのrouterから呼ばれる

※現時点ではhttp://localhost:3000/usersというアドレスでusersページにアクセス出来る

connect-mongoを導入

必要パッケージのインストー

$ npm install --save connect-mongo
$ npm install --save express-session
$ npm install --save mongoose

app.jsの変更

パッケージの読み込みとmongooseコネクションの確立

const mongoose = require('mongoose');
const session = require('express-session');
const mongoStore = require('connect-mongo')(session);

// localhost:27017 でMongoDBが起動している前提
mongoose.connect('mongodb://localhost:27017/connect-mongo-skt');

sessionを使うための準備

app.use(session({
  secret: 'test', 
  store: new mongoStore({ mongooseConnection: mongoose.connection })
}));

後でindex内でルーティングの設定を一括して行うため以下の部分はコメントアウトします。

// app.use('/users', users);

mongooseのスキーマ定義

$ mkdir models
$ touch models/userModel.js
const mongoose = require('mongoose');
let Schema = mongoose.Schema;

let UserSchema = new Schema({
  username: String,
  password: String,
});

module.exports = mongoose.model('Users', UserSchema);

index.jsの変更

ModelとViewファイルの読み込み

let User = require('../models/userModel.js');
let users = require('./users.js');
router.get('/', function(req, res, next) {
  // debug
  console.log(req.session);
  if (req.session.user) {
    // すでにログイン時
    res.redirect('/users')
  }
  res.render('login', { title: 'Express' });
});

/* ログイン */
router.post('/login', function(req, res, next) {
  // 簡単なバリデーション
  if (!req.body.username || !req.body.password) {
    res.redirect('/');
  }
  let query = {
    username: req.body.username,
    password: req.body.password // sha1などで暗号化するのがベター
  }
  User.find(query, function(err, data) {
    if (err) {
      // エラー発生時
      console.log(err);
      res.redirect('/');
    }
    if (data.length > 0) {
      // ログイン成功時
      req.session.user_id = data[0]._id;
      res.redirect('/users');
    }
    else {
      // ログイン失敗時
      res.redirect('/');
    }
  });
});

router.post('/register', function(req, res) {
  // 簡単なバリデーション
  if (!req.body.username || !req.body.password) {
    res.redirect('/');
  }
  let user = new User();
  user.username = req.body.username;
  user.password = req.body.password;
  user.save(function(err) {
    if (err) {
      console.log(err);
    }
    res.redirect('/');
  });
});

router.post('/logout', function(req, res) {
  delete req.session.user;
  res.redirect('/');
});

let loginCheck = (req, res, next) => {
  if (req.session.user_id) {
    next();
  } else {
    res.redirect('/');
  }
}

router.use('/users', loginCheck, users); // loginCheck

ログイン画面

サクッと試す目的で作成したため、ログイン画面とユーザー登録画面が単一になっています。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <h2>ログイン</h2>
  <form action="/login" method="POST">
    <input type="text" name="username"/>
    <input type="password" name="password"/>
    <input type="submit">ログイン</button>
  </form>

  <h2>新規登録</h2>
  <form action="/register" method="POST">
    <input type="text" name="username"/>
    <input type="password" name="password"/>
    <input type="submit">登録</button>
  </form>

</body>
</html>

以上、connect-mongoを使ってログイン機能をサクッと実装することが出来ました。

GitHub

github.com