Expressでログイン機能を実装してみる

--sessionオプションをつけると、ssessionオブジェクトが有効な状態でプロジェクトが作成されます。

 

$ express --sessions

 

既存のプロジェクトでセッション管理が必要になった場合は、app.jsのapp.use(app.router);の直ぐ上くらいに、以下の二行を追加します。

 

app.use(express.cookieParser('your secret here'));
app.use(express.session());

 

これで、sessionオブジェクトを使ってセッション管理ができるようになります。

 

以下が、そのsessionオブジェクトを使ったログイン機能の実装例です。

ほぼ、Expressのexampleのコピーですが、MongoDBなど使おうとするとこんな感じになるかなぁと思います。

 

// routes/index.js
var schema = require('../models')
  , User = schema.User
  , helpers = require('../lib/helpers');
 
exports.register = function(req, res) {
  var email = req.body.email
    , passwd = req.body.passwd;
 
  var user = new User({ email: email });
  user.hashPasswd(passwd, function(err) {
    if (err) return res.redirect('register');
 
    user.save(function(err) {
      if (err) return res.redirect('register');
      res.redirect('/');
    });
  })
}
 
exports.login = function(req, res) {
  helpers.authenticate(req.body.email, req.body.passwd, function(err, user) {
    if (user) {
      req.session.regenerate(function() {
        req.session.user = user;
        res.redirect('/');
      });
    } else {
      req.session.error = 'Authentication failed.';
      res.redirect('login');
    }
  });
}
 
exports.logout = function(req, res) {
  req.session.destroy(function() {
    res.redirect('/');
  })
} 

 

// models/user.js
var Schema = require('mongoose').Schema
  , helpers = require('../lib/helpers');
 
var Schema = module.exports = new Schema({
  email: { type: String, unique: true },
  salt: String,
  hash: Buffer,
});
 
Schema.statics.findByEmail = function(email, fn) {
  this.findOne({ email: email }, function(err, user){
    if (err || !user) return fn('cannot find user');
    fn(null, user);
  });
}
 
Schema.methods.hashPasswd = function(passwd, fn) {
  var self = this;
 
  if (!self.salt || !self.hash) {
    helpers.hash(passwd, function(err, salt, hash){
      self.salt = salt;
      self.hash = hash;
      fn(err);
    });
  } else {
    fn(null);
  }
}

 

 // lib/helpers.js
var crypto = require('crypto')
  , schema = require('../models')
  , User = schema.User;
 
var hash = exports.hash = function(passwd, salt, fn) {
  var len = 128
    , iterations = 12000;
 
  if (3 == arguments.length) {
    crypto.pbkdf2(passwd, salt, iterations, len, fn);
  } else {
    fn = salt;
    crypto.randomBytes(len, function(err, salt){
      if (err) return fn(err);
      salt = salt.toString('base64');
      crypto.pbkdf2(passwd, salt, iterations, len, function(err, hash){
        if (err) return fn(err);
        fn(null, salt, hash);
      });
    });
  }
}
 
exports.authenticate = function (email, passwd, fn) {
  User.findByEmail(email, function(err, user) {
    if (err) return fn(err);
    
    hash(passwd, user.salt, function(err, hash) {
      if (err) return fn(err);
      if (hash == user.hash) return fn(null, user);
      fn(new Error('invalid password'));
    });
  }); 
}

 

リモートのMongoDBをlocalhostのコンソールでいじりたい

リモートサーバのMongoDBのバージョンが低く、日本語が表示できなかったりしてコンソールが使いづらい。。

でも、バージョン上げるのダルいし。。

 

というときにsshのポート・フォワード機能とかいうのを使うと、ローカルのコンソールから触れるようになることを知ってしまった。

 

ssh -L 27018:localhost:27017 User@Host

 

これで、ポート番号27018を指定してコンソールを立ち上げればOKです。

 

$ mongo --port 27018

 

知っておくと意外なところで使えそう。

Node.jsでPassbookを発行してみる

node-passbookを使うと簡単に、NodeでPassbookを発行できました。

 

まずは、npmを使ってインストール 

$ npm install passbook


インストールが終わったら、以下のようにPassbookファイルを作成する処理を書きます。

var fs = require('fs')
  , createTemplate = require('passbook')
 
var template = createTemplate('coupon', {
  'teamIdentifier': '12345ABCDE',
  'passTypeIdentifier': 'pass.seeei.sample',
  'organizationName': 'Seeei Inc.'
});
 
template.keys('./etc/passbook/keys', '12345678'); 
 
var passbook = template.createPassbook({
  serialNumber: 'abcdefc',
  description: 'description!',
  logoText: 'Logo!',
  backgroundColor: '#ffffff'
});
 
passbook.images.icon = './public/images/icon.png';
passbook.images.logo = './public/images/logo.png';
passbook.generate(function(err, buffer) {
  if (err) throw err; 
 
  fs.writeFile('./public/passes/sample.pkpass', buffer, function(err) {
    console.log('Yeah!');
  });
}); 


このライブラリには、TemplateクラスとPassbookクラスが用意されていて、createTemplateには共通で使いたい値を、createPassbookにはPassごとに設定したい値を引数に渡してあげます。

 

ここでは、createTempleteにTeam IDやPass Type IDなどをハッシュで渡して、templateを作成しています。

 つぎに、そのtemplateに、証明書+秘密鍵のpemファイルが置いてあるパスと、設定したパスワードをもたせます。

 

この辺で必要になるIDやpemファイルの作り方は以下のサイトを参考にしました。

http://www.atotok.com/labo/ios_dev/20110404220418.html

http://www.ianlewis.org/jp/python-passbook 

 

あとは、createPassbookに適当な値を渡して、画像とかを設定して、".pkpass"という拡張子をつけたファイルに保存すれば準備完了。

Expressなら以下のような感じにして、iPhoneから落とせます。

exports.download = function(req, res){  var file = './public/passes/sample.pkpass'
    , filestream = fs.createReadStream(file)
    , filename = path.basename(file)
    , mimetype = 'application/vnd.apple.pkpass';
 
  res.setHeader('Content-disposition', 'attachment; filename=' + filename);
  res.setHeader('Content-type', mimetype); 
 
  filestream.on('data', function(chunk) {
    res.write(chunk);
  }); 
 
  filestream.on('end', function() {
    res.end();
  });
}