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.