Node.js
Express
Passport

node.js+express+passport.jsでlocal認証を試したメモ

More than 3 years have passed since last update.

前回までで、開発環境を作成したので認証を試す。


share/Docker/express/Dockerfile.

FROM node:5.4.0

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

#gulpfileを書き出し
RUN echo "var requireDir = require('require-dir'); requireDir('webapp/gulp/tasks', { recurse: true }); " > gulpfile.js

#package.jsonを書き出し
RUN echo '{ "name": "node_express", "scripts": { "start": "node webapp/bin/www", "gulp":"gulp" }}' > package.json

#タスクランナーインストール
RUN npm install --save-dev gulp
RUN npm install --save-dev require-dir
RUN npm install --save-dev gulp-if
RUN npm install --save-dev gulp-livereload

#サーバーインストール
RUN npm install --save-dev express
RUN npm install --save-dev body-parser
RUN npm install --save-dev cookie-parser
RUN npm install --save-dev debug
RUN npm install --save-dev jade
RUN npm install --save-dev morgan
RUN npm install --save-dev serve-favicon

# ウェブソケットインストール
RUN npm install --save-dev socket.io

# DBドライバインストール
RUN npm install --save-dev mongodb

# 認証ミドルウェアインストール
RUN npm install --save-dev passport
RUN npm install --save-dev passport-local
CMD [ "npm","run","gulp", "--","watch" ]



share/shell/express_docker_start.sh

#!/bin/bash 

source "/home/vagrant/share/shell/env.conf"

# 前回のコンテナが残っているかチェック。
docker ps -a | grep $containerName_express >/dev/null 2>&1

# コンテナが残っている場合は削除。
if [ $? -eq 0 ]; then
docker rm -f $containerName_express
fi

docker run --name $containerName_express --rm -it -p 80:3000 -p 35729:35729 -v $path_dev_dir/myExpressGenerator:/usr/src/app/webapp $imageName_express


dockerイメージを作成し、コンテナを作成する。

次に、ルーティングと認証の設定。


share/dev/myExpressGenerator/app.js

var express = require('express');

var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');

// ルート設定
var routes = require('./routes/index');
var users = require('./routes/users');
var insert = require('./routes/insert.js');
var login = require('./routes/login');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// 認証ミドルウェアpassportの初期化。
app.use(passport.initialize());

app.use('/', routes);
app.use('/users', users);
app.use('/insert', insert);
app.use('/login', login);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});

module.exports = app;



share/dev/myExpressGenerator/views/login.jade

extends layout

block content
h1=title
p Welcome to #{title}
p#id_test test
form(action="/login", method="post")
div
label
ユーザーID:
input(type="text", name="username")
div
label
パスワード:
input(type="password", name="password")
div
input(type="submit", value="ログイン")



share/dev/myExpressGenerator/routes/login.js

var express = require('express');

var router = express.Router();

var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
function(username, password, done) {
// テスト用ユーザー
var user = {id:"test", username:"user",password:"password"};

// 認証。
if(username===user.username && password===user.password){
return done(null, true);
}else{
return done(null, false, { message: 'ログインに失敗しました。' });
}
}
));

router.get('/',
function(req, res, next) {
res.render('login', { title: 'Login' });
});

router.post('/',
passport.authenticate('local', {failureRedirect: '/login',
failureFlash: false,
session: false }),
function(req, res, next){
res.send("login success");
}
);
module.exports = router;


これで、 http://192.168.50.10/loginにアクセスすると認証を試すことができる。

次に、セッションを試す。


share/Docker/express/Dockerfile.

FROM node:5.4.0

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

#gulpfileを書き出し
RUN echo "var requireDir = require('require-dir'); requireDir('webapp/gulp/tasks', { recurse: true }); " > gulpfile.js

#package.jsonを書き出し
RUN echo '{ "name": "node_express", "scripts": { "start": "node webapp/bin/www", "gulp":"gulp" }}' > package.json

#タスクランナーインストール
RUN npm install --save-dev gulp
RUN npm install --save-dev require-dir
RUN npm install --save-dev gulp-if
RUN npm install --save-dev gulp-livereload

#サーバーインストール
RUN npm install --save-dev express
RUN npm install --save-dev body-parser
RUN npm install --save-dev cookie-parser
RUN npm install --save-dev debug
RUN npm install --save-dev jade
RUN npm install --save-dev morgan
RUN npm install --save-dev serve-favicon

# ウェブソケットインストール
RUN npm install --save-dev socket.io

# DBドライバインストール
RUN npm install --save-dev mongodb

# 認証ミドルウェアインストール
RUN npm install --save-dev passport
RUN npm install --save-dev passport-local

#セッション管理ミドルウェアインストール
RUN npm install --save-dev express-session

CMD [ "npm","run","gulp", "--","watch" ]



share/dev/myExpressGenerator/app.js

var express = require('express');

var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');
var session = require('express-session'); //セッション追加
// ルート設定
var routes = require('./routes/index');
var users = require('./routes/users');
var insert = require('./routes/insert.js');
var login = require('./routes/login');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// セッションミドルウェア設定
app.use(session({ resave:false,saveUninitialized:false, secret: 'keyboar cat' }));

// 認証ミドルウェアpassportの初期化。
app.use(passport.initialize());
app.use(passport.session()); // セッション追加

// ルーティング設定
app.use('/', routes);
app.use('/users', users);
app.use('/insert', insert);
app.use('/login', login);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});

module.exports = app;



share/dev/myExpressGenerator/routes/login.js

var express = require('express');

var router = express.Router();

var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
//データベースモック。
var db={
users:{
records:[{
id:"1",
username:"user",
password:"password",
name:"Hibohiboo"
}],
findById(id, cb) {
process.nextTick(() => {
var idx = id - 1;
var record=this.records[idx];
if (record) {
cb(null, record);
} else {
cb(new Error('User ' + id + ' does not exist'));
}
});
},
findByUsername(username, cb){
process.nextTick(()=> {
for (var i = 0, len = this.records.length; i < len; i++) {
var record = this.records[i];
if (record.username === username) {
return cb(null, record);
}
}
return cb(null, null);
});
}
}
}

passport.use(new LocalStrategy(
function(username, password, cb) {
db.users.findByUsername(username, function(err, user) {
if (err) { return cb(err); }
if (!user) { return cb(null, false); }
if (user.password != password) { return cb(null, false); }
return cb(null, user);
});
}
));

// Configure Passport authenticated session persistence.
passport.serializeUser(function(user, cb) {
cb(null, user.id);
});

passport.deserializeUser(function(id, cb) {
db.users.findById(id, function (err, user) {
if (err) { return cb(err); }
cb(null, user);
});
});

router.get('/',
function(req, res, next) {
res.render('login', { title: 'Login' });
});

router.post('/',
passport.authenticate('local', {
failureRedirect: '/login',
failureFlash: false}),
function(req, res, next){
res.render('login', { title: 'Login', user_name:req.user && req.user.name || "" });
}
);
module.exports = router;


extends layout

block content
h1= title
p Welcome to #{title}
p#id_test #{user_name}
form(action="/login", method="post")
div
label
ユーザーID:
input(type="text", name="username")
div
label
パスワード:
input(type="password", name="password")
div
input(type="submit", value="ログイン")

ログインすると、名前が表示される。


参考サイト

document - passport

express-session

Node.js + Express.js + express-sessionでセッションにデータ格納する方法

express-4.x-local-example