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')); }); }); }