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