LoginSignup
30
35

More than 5 years have passed since last update.

Express4 + Passportでログイン認証をしてみる

Last updated at Posted at 2015-11-30

はじめに

Passportとはログイン認証に便利なライブラリ。
ただ巷で溢れるサンプルはだいたいExpress3.xで書かれているので、Express4用にメモ。
OAuthだとかOpenIDを使った認証もあるけど、
今回はシンプルにユーザー、パスワードのみで認証してみます。

詳しくはこちら。コードがExpress3だけど。
Passport(公式ページ)
日本語訳ページ

バージョン

node.js - 0.12.7
express - 4.13.1
passport - 0.3.2

実装

まずはモデル。認証情報を保持する。

account.js
'use strict';

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var AccountSchema = new Schema({
    id: { type: String, required: true },
    password: { type: String, required: true },
    updated_at: { type: Date },
    created_at: { type: Date }
});

AccountSchema.pre('save', function(next) {
    var now = new Date();
    this.updated_at = now;
    if (!this.created_at) {
        this.created_at = now;
    }
    next();
});

module.exports = mongoose.model('Account', AccountSchema);

次にapp.js。

app.js
var express = require('express');
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var session = require('express-session');
var crypto = require('crypto');
var app = express();

app.use(session({ secret: 'hoge' }));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
var LocalStrategy = require('passport-local').Strategy;

// 認証
passport.use(new LocalStrategy(
    {
        usernameField: 'name',
        passwordField: 'password',
        passReqToCallback: true
    },
    function (req, name, password, done) {
        process.nextTick(function () {
            var Account = mongoose.model('Account');
            Account.findOne({ "id": name }, function (err, account) {
                if (err) return done(err);
                if (!account) {
                    req.flash('error', 'ユーザーが見つかりませんでした。');
                    req.flash('input_id', name);
                    req.flash('input_password', password);
                    return done(null, false);
                }
                var hashedPassword = getHash(password);
                if (account.password != hashedPassword
                    && account.password != password) {
                    req.flash('error', 'パスワードが間違っています。');
                    req.flash('input_id', name);
                    req.flash('input_password', password);
                    return done(null, false);
                }
                return done(null, account);
            });
        })
    }
));

// 暗号化
var getHash = function(value) {
    var sha = crypto.createHmac('sha256', 'secretKey');
    sha.update(value);
    return sha.digest('hex');
};

// passport
passport.serializeUser(function (account, done) {
    done(null, account.id);
});
passport.deserializeUser(function (serializedAccount, done) {
    var Account = mongoose.model('Account');
    Account.findOne({ "id": serializedAccount }, function (err, account) {
        done(err, account.id);
    });
});

routingとかsessionの有無チェックとかは省略しております。
ポイントはpassReqToCallbacktrueにしてリクエストを取得すること。
で、connect-flashのライブラリを読み込んで、入力値やエラーメッセージを設定しています。
usernameFieldpasswordField はhtmlのテキストフィールド'name'値です。

次にログイン処理。

login.js
'use strict';

var express = require('express');
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var router = express.Router();

// ログイン画面表示
router.get('/', function (req, res) {
    res.render('login', {
        error: req.flash('error'),
        input_id: req.flash('input_id'),
        input_password: req.flash('input_password')
    });
});

// ログイン情報入力
router.post('/', function(req, res, next) {
    passport.authenticate('local', {
        successRedirect: '/',
        failureRedirect: '/login',
        failureFlash: true
    })(req, res, next);
});

module.exports = router;

app.jsflashした値をここで取得してrenderしてやる。

login.ejs
<!DOCTYPE html>
<html lang="ja">
<body>
    <p><%= error %</p>
    <form action="/login" method="POST">
    ID:
    <input type="text" name="name" value="<%= input_id %>">
    Password:
    <input type="password" name="password" value="<%= input_password >">
    <input type="submit" value="ログイン">
    </form>
</body>
</html>
30
35
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
30
35