Database-based login/logout
This commit is contained in:
parent
02083af4a9
commit
c5393b050e
38
app.js
38
app.js
@ -3,6 +3,7 @@
|
|||||||
// ------------ Basic Dependencies -------------------------------------------
|
// ------------ Basic Dependencies -------------------------------------------
|
||||||
var express = require('express'),
|
var express = require('express'),
|
||||||
session = require('express-session'),
|
session = require('express-session'),
|
||||||
|
csrf = require('csurf'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
favicon = require('serve-favicon'),
|
favicon = require('serve-favicon'),
|
||||||
logger = require('morgan'),
|
logger = require('morgan'),
|
||||||
@ -11,7 +12,7 @@ var express = require('express'),
|
|||||||
requireDir = require('require-dir'),
|
requireDir = require('require-dir'),
|
||||||
connection = require('express-myconnection'),
|
connection = require('express-myconnection'),
|
||||||
bcrypt = require('bcrypt-nodejs'),
|
bcrypt = require('bcrypt-nodejs'),
|
||||||
mysql = require('mysql');
|
mysql = require('mysql2');
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
var app = express();
|
var app = express();
|
||||||
|
|
||||||
@ -20,13 +21,13 @@ app.set('trust proxy', true); // Trust X-Forwarded-* headers
|
|||||||
|
|
||||||
// Database connection
|
// Database connection
|
||||||
app.use(
|
app.use(
|
||||||
connection('mysql', {
|
connection(mysql, {
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
user: 'node',
|
user: 'node',
|
||||||
password: 'node',
|
password: 'node',
|
||||||
port: 3306,
|
port: 3306,
|
||||||
database: 'node'
|
database: 'node'
|
||||||
}, 'request')
|
}, 'pool')
|
||||||
);
|
);
|
||||||
|
|
||||||
// view engine setup
|
// view engine setup
|
||||||
@ -42,7 +43,28 @@ app.use(logger('dev'));
|
|||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: false }));
|
app.use(bodyParser.urlencoded({ extended: false }));
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
|
app.use(session({
|
||||||
|
resave: true,
|
||||||
|
saveUninitialized: true,
|
||||||
|
secret: 'j2uyc0hjh2;clkjang1ddojj'
|
||||||
|
}));
|
||||||
app.use(express.static(path.join(__dirname, 'public'), {redirect:false}));
|
app.use(express.static(path.join(__dirname, 'public'), {redirect:false}));
|
||||||
|
app.use(csrf({
|
||||||
|
ignoreMethods: ['GET', 'HEAD', 'OPTIONS']
|
||||||
|
}));
|
||||||
|
|
||||||
|
//Check session for any pages that require authentication
|
||||||
|
app.use(function(err, req, res, next) {
|
||||||
|
if ( ! req.session.uid)
|
||||||
|
{
|
||||||
|
console.log("This should redirect to index!")
|
||||||
|
|
||||||
|
['/', '/login', '/logout'].forEach(function(item) {
|
||||||
|
if (req.path.match(item)) return next();
|
||||||
|
});
|
||||||
|
res.redirect(303, '/');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Route mapping
|
// Route mapping
|
||||||
// Routes are prefixed by the filename,
|
// Routes are prefixed by the filename,
|
||||||
@ -54,6 +76,7 @@ Object.keys(routes).forEach(function(route) {
|
|||||||
var path = (route != 'index')
|
var path = (route != 'index')
|
||||||
? '/' + route
|
? '/' + route
|
||||||
: '/';
|
: '/';
|
||||||
|
|
||||||
app.use(path, routes[route]);
|
app.use(path, routes[route]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -66,6 +89,15 @@ app.use(function(req, res, next) {
|
|||||||
|
|
||||||
// error handlers
|
// error handlers
|
||||||
|
|
||||||
|
// csrf error handler
|
||||||
|
app.use(function(err, req, res, next) {
|
||||||
|
if (err.code !== 'EBADCSRFTOKEN') return next(err);
|
||||||
|
|
||||||
|
// Bad CSRF Token
|
||||||
|
res.status(403);
|
||||||
|
res.send('Session has expired, or has been tampered with.');
|
||||||
|
});
|
||||||
|
|
||||||
// development error handler
|
// development error handler
|
||||||
// will print stacktrace
|
// will print stacktrace
|
||||||
if (app.get('env') === 'development') {
|
if (app.get('env') === 'development') {
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"dustjs-linkedin":"*",
|
"dustjs-linkedin":"*",
|
||||||
"dustjs-helpers":"*",
|
"dustjs-helpers":"*",
|
||||||
"nodeunit":"*",
|
"nodeunit":"*",
|
||||||
"mysql":"*",
|
|
||||||
"node-memcache":"*"
|
"node-memcache":"*"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,73 @@
|
|||||||
var express = require('express');
|
var express = require('express');
|
||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
|
|
||||||
/* GET home page. */
|
/* GET Home / Login Form */
|
||||||
router.get('/', function(req, res) {
|
router.get('/', function(req, res) {
|
||||||
res.render('index', { title: 'Express'});
|
var util = require('util');
|
||||||
|
var request = util.inspect(req, {depth: 2});
|
||||||
|
|
||||||
|
// If the user isn't logged in
|
||||||
|
if ( ! req.session.uid)
|
||||||
|
{
|
||||||
|
res.render('login', {
|
||||||
|
title: 'Node Task Manager',
|
||||||
|
csrfToken: req.csrfToken()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.render('index', {
|
||||||
|
title: 'Node Task Manager',
|
||||||
|
user: req.session.username,
|
||||||
|
req: request
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Login action */
|
||||||
|
router.post('/login', function(req, res) {
|
||||||
|
var bcrypt = require('bcrypt-nodejs');
|
||||||
|
|
||||||
|
var user = req.body.user,
|
||||||
|
pass = req.body.pass;
|
||||||
|
|
||||||
|
req.getConnection(function(err, connection) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
var sql = " SELECT id, username, email, password, timezone, num_format " +
|
||||||
|
" FROM todo_user " +
|
||||||
|
" WHERE email = ? OR username = ? ";
|
||||||
|
|
||||||
|
// Find the username / email
|
||||||
|
connection.execute(sql, [user, user], function(err, rows, fields) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
var user = rows[0];
|
||||||
|
|
||||||
|
// Verify the password hash
|
||||||
|
bcrypt.compare(pass, user.password, function(err, passRes) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
// Password is good, set session data and redirect
|
||||||
|
if (passRes === true)
|
||||||
|
{
|
||||||
|
req.session.uid = user.id;
|
||||||
|
req.session.num_format = user.num_format;
|
||||||
|
req.session.username = user.username;
|
||||||
|
|
||||||
|
res.redirect(303, '/');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Logout action */
|
||||||
|
router.get('/logout', function(req, res) {
|
||||||
|
// Destroy the session, and redirect to the index page
|
||||||
|
req.session.destroy(function(err) {
|
||||||
|
res.redirect(303, '/');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
@ -3,7 +3,23 @@ var router = express.Router();
|
|||||||
|
|
||||||
/* GET list of tasks */
|
/* GET list of tasks */
|
||||||
router.get('/list', function(req, res) {
|
router.get('/list', function(req, res) {
|
||||||
res.json([{}]);
|
req.getConnection(function(err, connection) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
var uid = req.session.uid;
|
||||||
|
|
||||||
|
if ( ! uid)
|
||||||
|
{
|
||||||
|
console.log("Redirect because of bad session in list route");
|
||||||
|
res.redirect('/');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.execute('SELECT * from todo_task_view WHERE user_id=?', [uid], function(err, rows) {
|
||||||
|
if (err) throw err;
|
||||||
|
res.json(rows);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
1
views/csrf.dust
Normal file
1
views/csrf.dust
Normal file
@ -0,0 +1 @@
|
|||||||
|
<input type="hidden" name="_csrf" value="{csrfToken}" />
|
@ -1,6 +1,6 @@
|
|||||||
{>layout/}
|
{>layout/}
|
||||||
|
|
||||||
{<content}
|
{<content}
|
||||||
<h1>{title}</h1>
|
<p>Hi, {user}. Welcome to {title}</p>
|
||||||
<p>Welcome to {title}</p>
|
<pre>{req}</pre>
|
||||||
{/content}
|
{/content}
|
||||||
|
@ -2,17 +2,29 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
<link rel='stylesheet' href='/css/style.css' />
|
<link rel="stylesheet" href="/css/ink.min.css" />
|
||||||
|
<link rel="stylesheet" href="/css/ink-flex.min.css" />
|
||||||
|
<link rel="stylesheet" href="/css/font-awesome.min.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<header class="ink-grid">
|
||||||
|
<h1>{title}</h1>
|
||||||
|
<nav class="ink-navigation">
|
||||||
|
<ul class="menu horizontal">
|
||||||
|
<li><a href="/logout">Logout</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main class="ink-grid">
|
||||||
{+content}
|
{+content}
|
||||||
This is the base content.
|
This is the base content.
|
||||||
{/content}
|
{/content}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
||||||
|
<script src="/js/native.history.js"></script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
{session}
|
{session}
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
|
||||||
<script src="/js/native.history.js"></script>
|
|
||||||
</html>
|
</html>
|
||||||
|
27
views/login.dust
Normal file
27
views/login.dust
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{>layout/}
|
||||||
|
|
||||||
|
{<content}
|
||||||
|
<form class="ink-form column-group" action="/login" method="post">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Login</legend>
|
||||||
|
<div class="control-group required">
|
||||||
|
<label for="user">Username / Email Address</label>
|
||||||
|
<div class="control">
|
||||||
|
<input type="text" name="user" id="user" required="required" />
|
||||||
|
</div>
|
||||||
|
<p class="tip">This field is required</p>
|
||||||
|
</div>
|
||||||
|
<div class="control-group required">
|
||||||
|
<label for="pass">Password</label>
|
||||||
|
<div class="control">
|
||||||
|
<input type="password" name="pass" id="pass" required="required" />
|
||||||
|
</div>
|
||||||
|
<p class="tip">This field is required</p>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<input type="hidden" name="_csrf" value="{csrfToken}" />
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
{/content}
|
Reference in New Issue
Block a user