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

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

```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][link-1]
[express-session][link-2]
[Node.js + Express.js + express-sessionでセッションにデータ格納する方法][link-3]
[express-4.x-local-example
][link-4]

[link-1]:http://passportjs.org/docs/username-password
[link-2]:https://github.com/expressjs/session
[link-3]:http://qiita.com/moomoo-ya/items/00f89e425a3034b8ea14
[link-4]:https://github.com/passport/express-4.x-local-example
[link-5]:http://qiita.com/hibohiboo/items/f7988c3801c392e5d141