135 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict'
 | |
| 
 | |
| /**
 | |
|  * Module dependencies.
 | |
|  */
 | |
| 
 | |
| var express = require('../..');
 | |
| var hash = require('pbkdf2-password')()
 | |
| var path = require('node:path');
 | |
| var session = require('express-session');
 | |
| 
 | |
| var app = module.exports = express();
 | |
| 
 | |
| // config
 | |
| 
 | |
| app.set('view engine', 'ejs');
 | |
| app.set('views', path.join(__dirname, 'views'));
 | |
| 
 | |
| // middleware
 | |
| 
 | |
| app.use(express.urlencoded())
 | |
| app.use(session({
 | |
|   resave: false, // don't save session if unmodified
 | |
|   saveUninitialized: false, // don't create session until something stored
 | |
|   secret: 'shhhh, very secret'
 | |
| }));
 | |
| 
 | |
| // Session-persisted message middleware
 | |
| 
 | |
| app.use(function(req, res, next){
 | |
|   var err = req.session.error;
 | |
|   var msg = req.session.success;
 | |
|   delete req.session.error;
 | |
|   delete req.session.success;
 | |
|   res.locals.message = '';
 | |
|   if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
 | |
|   if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
 | |
|   next();
 | |
| });
 | |
| 
 | |
| // dummy database
 | |
| 
 | |
| var users = {
 | |
|   tj: { name: 'tj' }
 | |
| };
 | |
| 
 | |
| // when you create a user, generate a salt
 | |
| // and hash the password ('foobar' is the pass here)
 | |
| 
 | |
| hash({ password: 'foobar' }, function (err, pass, salt, hash) {
 | |
|   if (err) throw err;
 | |
|   // store the salt & hash in the "db"
 | |
|   users.tj.salt = salt;
 | |
|   users.tj.hash = hash;
 | |
| });
 | |
| 
 | |
| 
 | |
| // Authenticate using our plain-object database of doom!
 | |
| 
 | |
| function authenticate(name, pass, fn) {
 | |
|   if (!module.parent) console.log('authenticating %s:%s', name, pass);
 | |
|   var user = users[name];
 | |
|   // query the db for the given username
 | |
|   if (!user) return fn(null, null)
 | |
|   // apply the same algorithm to the POSTed password, applying
 | |
|   // the hash against the pass / salt, if there is a match we
 | |
|   // found the user
 | |
|   hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) {
 | |
|     if (err) return fn(err);
 | |
|     if (hash === user.hash) return fn(null, user)
 | |
|     fn(null, null)
 | |
|   });
 | |
| }
 | |
| 
 | |
| function restrict(req, res, next) {
 | |
|   if (req.session.user) {
 | |
|     next();
 | |
|   } else {
 | |
|     req.session.error = 'Access denied!';
 | |
|     res.redirect('/login');
 | |
|   }
 | |
| }
 | |
| 
 | |
| app.get('/', function(req, res){
 | |
|   res.redirect('/login');
 | |
| });
 | |
| 
 | |
| app.get('/restricted', restrict, function(req, res){
 | |
|   res.send('Wahoo! restricted area, click to <a href="/logout">logout</a>');
 | |
| });
 | |
| 
 | |
| app.get('/logout', function(req, res){
 | |
|   // destroy the user's session to log them out
 | |
|   // will be re-created next request
 | |
|   req.session.destroy(function(){
 | |
|     res.redirect('/');
 | |
|   });
 | |
| });
 | |
| 
 | |
| app.get('/login', function(req, res){
 | |
|   res.render('login');
 | |
| });
 | |
| 
 | |
| app.post('/login', function (req, res, next) {
 | |
|   if (!req.body) return res.sendStatus(400)
 | |
|   authenticate(req.body.username, req.body.password, function(err, user){
 | |
|     if (err) return next(err)
 | |
|     if (user) {
 | |
|       // Regenerate session when signing in
 | |
|       // to prevent fixation
 | |
|       req.session.regenerate(function(){
 | |
|         // Store the user's primary key
 | |
|         // in the session store to be retrieved,
 | |
|         // or in this case the entire user object
 | |
|         req.session.user = user;
 | |
|         req.session.success = 'Authenticated as ' + user.name
 | |
|           + ' click to <a href="/logout">logout</a>. '
 | |
|           + ' You may now access <a href="/restricted">/restricted</a>.';
 | |
|         res.redirect(req.get('Referrer') || '/');
 | |
|       });
 | |
|     } else {
 | |
|       req.session.error = 'Authentication failed, please check your '
 | |
|         + ' username and password.'
 | |
|         + ' (use "tj" and "foobar")';
 | |
|       res.redirect('/login');
 | |
|     }
 | |
|   });
 | |
| });
 | |
| 
 | |
| /* istanbul ignore next */
 | |
| if (!module.parent) {
 | |
|   app.listen(3000);
 | |
|   console.log('Express started on port 3000');
 | |
| }
 |