--- templateEngineOverride: false ---
Dr. Greg M. Bernstein
Updated April 18th, 2021
express-session
Express Middleware to help us:
express-session
Uses other packages for:
request
parameter for easy use by our software.For all files get SessionExample.zip
Application specific access control!
General GET paths:
Login related paths, open to all:
Event adding only for members:
Uses Nunjucks templates
base.njk
: Contains HTML boilerplate and site menu. All other templates inherit from this.
Specific purpose templates: addEvent.njk
, events.njk
, goodbye.njk
, loginError.njk
, users.njk
, Forbidden.njk
, index.njk
, logon.njk
, welcome.njk
Parent of all other templates, includes site navigation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
{% block title %}
<title>This is where the title goes</title>
{% endblock %}
<style>
#Menu {
display: flex;
list-style: none;
justify-content: space-around;
}
#CurUser {
background-color: blue;
color: white;
font-family: Sans-Serif;
}
</style>
{% block style %}
{% endblock %}
</head>
<body>
<ul id="Menu">
<li><a href="/">Home</a></li>
<li><a href="events">Events</a></li>
<li><a href="addEventForm">Add Event</a></li>
<li><a href="users">Users</a></li>
<li><a href="loginForm">Login</a></li>
<li><a href="logout">Logout</a></li>
</ul>
{% if user and user.loggedin %}
<p id="CurUser">User: {{ user.firstName }} {{ user.lastName }}</p>
{% endif %}
<main>
{% block content %}
{% endblock %}
</main>
</body>
</html>
Example specific use template
{% extends "base.njk" %}
{% block title %}
<title>Forbidden!</title>
{% endblock %}
{% block style %}
<style>
body {margin: 1em;}
main {background-color: #FCABA1;
padding: 0.5em;
font-family: sans-serif;}
h1, h2 {text-align: center}
</style>
{% endblock %}
{% block content %}
<h1>Forbidden</h1>
<h2>You must be logged in to perform this operation or see this information.</h2>
{% endblock %}
Sets up cookie processing and session storage retrieval:
const session = require('express-session');
// change cookie name from default
const cookieName = "clubsid"; // Session ID cookie name, use this to delete cookies too.
// Create the session middleware and put it into general use
app.use(session({
secret: 'website development CSUEB',
resave: false,
saveUninitialized: false,
name: cookieName // Sets the name of the cookie used by the session middleware
}));
It is up to us to decide what goes into the session storage:
// This initializes session state
const setUpSessionMiddleware = function (req, res, next) {
// We can attach any state/info we like to the session JS object
// Below we add a user property.
if (!req.session.user) { // Check for state or initialize it
req.session.user = {loggedin: false};
}
next();
};
app.use(setUpSessionMiddleware); // Put it to use!
Initial visit to homepage:
Visiting /users
prior to login:
We have a number of different paths to protect so we come up with some middleware:
// Use this middleware to restrict paths to only logged in users
const checkLoggedInMiddleware = function (req, res, next) {
if (!req.session.user.loggedin) {
res.render("Forbidden.njk");
} else {
next();
}
};
Protecting paths with the middleware:
// Only available to logged in members
app.get('/users', checkLoggedInMiddleware, function (req, res) {
res.render('users.njk', {users: users, user: req.session.user});
});
// Only available to logged in members
app.get('/addEventForm', checkLoggedInMiddleware, function (req, res) {
res.render('addEvent.njk', {user: req.session.user});
});
// Other protected paths...
Per OWASP recommendations we should generate a new session ID
app.post('/logon', express.urlencoded({extended:true}), function (req, res) {
console.log(req.body);
let email = req.body.email;
let password = req.body.password;
// Find user
let auser = users.find(function (user) {
return user.email === email
});
if (!auser) {// Not found
res.render("loginError.njk");
return;
}
let verified = bcrypt.compareSync(password, auser.passHash);
if (verified) {
// Upgrade in priveledge, should generate new session id
// Save old session information if any, create a new session
let oldInfo = req.session.user;
req.session.regenerate(function (err) {
if (err) {
console.log(err);
}
req.session.user = Object.assign(oldInfo, auser, {
loggedin: true
});
res.render("welcome.njk", {user: auser});
});
} else {
res.render("loginError.njk");
}
});
Note that session ID has not changed.
Session ID changes, site knows user name:
Same session ID as after login
Removing the cookie on logout:
We destroy the session, and also show how to remove the cookie
app.get('/logout', function (req, res, next) {
let options = req.session.cookie;
req.session.destroy(function (err) {
res.clearCookie(cookieName, options); // the cookie name and options
res.render("goodbye.njk");
})
});
After logging out