I cannot believe how difficult it was to do something so simple. The bulk of the reason behind this, I believe, is the lack of documentation.
It always starts at App.js:
var express = require('express'); ... var app = express(); app.configure(function() { ... app.use(express.bodyParser()); ... app.use(express.cookieParser('secret')); ... app.use(express.session()); app.use(app.router); ... }); ... app.get('/', routes.index); app.get('/loginf', routes.loginf); app.post('/login', routes.login); app.get('/logout', routes.logout);
These set up the app to:
- bodyParser: parse form submissions and put the parsed parameters into req.body
- cookieParser: parse cookie values when present
- session: session support
- router: URL routing support
exports.index = function(req, res) { // If the session has a username, echo it to the view res.render('index', {username:req.session.username}); }; exports.loginf = function(req, res) { // render the login form res.render('loginf', {}); }; exports.login = function(req, res) { // extract the submitted form and record the user name // in the session var userName = req.body.username; var password = req.body.password; req.session.username = userName; res.redirect('/'); }; exports.logout = function(req, res) { // clear out the session req.session.destroy(); res.redirect('/'); };
The index view (views/index.jade) either displays the current user name or offers a link to log in.
doctype 5 html body - if (typeof username != 'undefined') div User #{username} div a(href='/logout') Log out - else div a(href='/loginf') Login please
html body table form(method='POST',action='/login') tr td div User Name td input(type='text',name='username') tr td div Password td input(type='text',name='password') tr td(colspan='2') input(type='submit',value='Log in')
Turns out the indentation matters in Jade, just like in Python. If A and B are in the same column, they are siblings. If B is indented further than and below A, then B is a child element of A.
Things yet to be figured out
All calls to render the ‘index’ view (or any other view that needs to know whether a user is logged in) currently needs to explicitly set the model’s “username” property. Is there an easier way? That is, can a Jade file access the session object?
Is there an interception/filter mechanism to reroute to the ‘loginf’ view if there is no “username” in the session, so that I don’t have to do this on every controller that requires a logged in user?
Turns out the answer is the various “middleware” components appended to “app” in app.js. This article describes it.