I want to check user authentication before showing a html page
my server.js file is like this
const express = require('express');
var jquery = require('jquery');
var admin = require("firebase");
const app = express();
app.use(express.static(__dirname + '/public'));
var serviceAccount = require("firebasekey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://23442344114.firebaseio.com"
});
var ref = admin.app().database().ref();
app.get(['/','/index.html'], function(req, res) {
res.sendFile(__dirname + '/public/index.html');
});
app.get(['/dash' ], function(req, res) {
res.sendFile(__dirname + '/public/dash/index.html');
});
How could I check if a user is authenticated first on the server side before rendering a page; for example,
app.get(['/dash' ], function(req, res) {
//check if the user is authenticated
if auth == true {
res.sendFile(__dirname + '/public/dash/index.html');
} else{
res.sendFile(__dirname + '/public/login.html');
}
});
how do I check the user authentication status on the server side?
As suggested, there are countless ways to authenticate your users.
But i will help you out with a simple example:
You should have a persistent list of your users e.g. database. For the simplicity we will go with a constant in your code.
const express = require('express');
var jquery = require('jquery');
var admin = require("firebase");
const USER = {
email: "john#doe.com",
password: "12345"
}
There are several ways to implement the authentication check. I would recommend using a middleware which can be applied to various routes:
const authenticate = (req, res, next) => {
// parse the user out of your request
// e.g with bodyparser -> see npm
if (req.body.email === USER.email && req.body.password === USER.password) {
next()
} else {
res.send({ status: 401 });
}
}
Apply this middleware to the routes you want to protect or to all routes
// all routes
app.use(authenticate)
// certain route
app.get('/someRoute', authenticate, (req, res)) => {
// only successful authenticated user
// (in this case: john#doe.com) will
// have access to this route.
// ... code
}
This pattern can be extended with e.g cookies, jwt and of course a database where you can store your registered users.
You should read about Authentication methods like JWT and OAuth. You can use a middleware to check if a particular user is authenticated or not. You can you libraries like passport for this. You can create you own router level middleware like this.
let middleware = function (req, res, next) {
//Do your checking...
next();
};
app.get(['/dash' ],middleware, function(req, res) {
//check if the user is authenticated
if auth == true {
res.sendFile(__dirname + '/public/dash/index.html');
} else {
res.sendFile(__dirname + '/public/login.html');
}
});
Related
I'm trying to set up a "backend" for a webpage I've created. So some pages can only be accessible if the user is logged in. I've built the basic functionality for this and I can do a simple validation in whether the user is logged-in. But the redirecting to the page is where I get stuck.
Example:
var auth = function(req,res,next){
if (req.session.loggedin){
return next();
} else{
return res.sendStatus(401);
}
};
app.get('/list-video', auth, function (req, res) {
res.redirect('/list-video');
});
So my issue is that '/list-video' is the page I want to protect and only be accessible when the user successfully logged in. But after the validation, I'm redirecting to the same page: '/list-video'. this doesn't seem to work as I'm obviously getting stuck in a loop. I have tried redirecting to a different page like '/list-audio' and of course this works fine.
Can someone advise on how this is usually done? Do I need to create a separate link that I can redirect to? (I do want to prevent users going to that link manually by typing the URL in the browser.)
Any help or advice will be greatly appreciated!
My complete app.js code:
const express = require('express');
const fileUpload = require('express-fileupload');
const bodyParser = require('body-parser');
const mysql = require('mysql');
const path = require('path');
const app = express();
const session = require('express-session');
const { getHomePage } = require('./routes/index');
const { getBackendPage } = require('./routes/backend');
const { getVideoPage, listVideoPage, editVideoPage, editVideo, deleteVideo, addVideoPage, addVideo } = require('./routes/video');
const { getEbookPage } = require('./routes/ebook');
const { getMusicPage } = require('./routes/music');
const { getGamePage } = require('./routes/game');
const { getShopPage } = require('./routes/shop');
const port = 5000;
const db = mysql.createConnection({
host: '127.0.0.1',
user: 'user',
password: 'bla',
database: 'test'
db.connect((err) => {
if (err) {
throw err;
}
console.log('Connected to database');
});
global.db = db;
// configure middleware
app.set('port', process.env.port || port); // set express to use this port
app.set('views', __dirname + '/views'); // set express to look in this folder to render our view
app.set('view engine', 'ejs'); // configure template engine
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json()); // parse form data client
app.use(express.static(path.join(__dirname, 'public'))); // configure express to use public folder
app.use(fileUpload()); // configure fileupload
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true
}));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
/ passenger views
app.get('/', getHomePage);
app.get('/backend', getBackendPage);
app.get('/video', getVideoPage);
app.get('/ebook', getEbookPage);
app.get('/music/:id', getMusicPage);
app.get('/game', getGamePage);
app.get('/shop', getShopPage);
// backend views video
app.get('/edit-video/:id', editVideoPage);
app.post('/edit-video/:id', editVideo);
app.get('/add-video', addVideoPage);
app.post('/add-video', addVideo);
app.get('/delete-video/:id', deleteVideo);
// login screen
app.post('/auth', function (request, response) {
var username = request.body.username;
var password = request.body.password;
if (username && password) {
db.query('SELECT * FROM accounts WHERE username = ? AND password = ?', [username, password], function (error, results, fields) {
if (results.length > 0) {
request.session.loggedin = true;
request.session.username = username;
response.redirect('/');
} else {
response.send('Incorrect Username and/or Password!');
}
response.end();
});
} else {
response.send('Please enter Username and Password!');
response.end();
}
});
var auth = function(req,res,next){
if (req.session.loggedin){
return next();
} else{
return res.sendStatus(401);
}
};
app.get('/list-video', auth, function (req, res) {
res.redirect('/list-video');
});
app.listen(port, () => {
console.log(`Server running on port: http://localhost:${port}`);
});
Move your protected pages to a different directory (outside the folder where your public static files are) and serve the express.static after the authentication middleware, something like this:
app.use('/', express.static(path.join(__dirname, 'public'))); //notice I have no auth middleware
app.use('/mysecretpages', auth, express.static(path.join(__dirname, 'secret'))); //notice I DO have auth middleware
change it to:
var auth = function(req,res,next){
if (!req.session.loggedin){
return res.redirect("/login");
} else{
return next();
}
};
app.get('/list-video', auth);
That way you will redirect to the login page if the user isn't authenticated and continue if he is.
I have this simple enough express application which tries to use Active Directory to authenticate the user. Here is my setup:
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const ActiveDirectoryStrategy = require('passport-activedirectory');
const PORT = process.env.PORT || 8080;
// AD configuration. Real values omitted.
const config = {
url: 'ldaps://...',
baseDN: '...',
username: '...',
password: '...'
};
const app = express();
app.use(session({
secret: 'mysessionsecret',
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use('ad', new ActiveDirectoryStrategy(
{
ldap: config
},
(profile, ad, done) => {
// The problem is here! This never gets called!
console.log('ActiveDirectoryStrategy activated.');
done('ActiveDirectoryStrategy not implemented.');
}
));
// route middleware to ensure user is logged in
const isLoggedIn = (req, res, next) =>
req.isAuthenticated() ? next() : res.redirect('/auth');
app.get('/', isLoggedIn, (req, res) => {
res.end('You are logged in.');
});
app.get('/unsecured', (req, res) => {
res.end('You are not logged in.');
});
app.get('/auth', passport.authenticate('ad', {
successRedirect: '/',
failureRedirect: '/unsecured'
}));
app.listen(PORT);
console.log('Listening on port ' + PORT);
However, the verifier function I pass for the constructor ActiveDirectoryStrategy never gets called. (This is the function with the signature (profile, ad, done)).
I am sure that there is no problem with the LDAP configuration, because I can access the active directory just fine with activedirectory module with the same parameters:
const ActiveDirectory = require('activedirectory');
const ad = new ActiveDirectory(config);
ad.findUser('username', (err, user) => {
if (err) {
return console.log(err);
}
console.log(JSON.stringify(user));
// prints an object with user's info
});
So there must be a problem with my routing. What am I doing wrong? Why is my verifier function not getting called?
The problem was a misconception I had. I thought the Passport.js's authenticate middleware would perform the NTLM handshake for me. This is not the case. passport-activedirectory actually needs something like IISNode to run in front of it in order to perform the NTLM handshake. Since the request does not contain the authentication information,
I settled on using express-ntlm middleware as a result. express-ntlm gives you the UserName, DomainName, and Workstation properties you can use. But if you want to acquire the full AD profile for some reason, you could setup a custom passport strategy like so:
const ActiveDirectory = require('activedirectory');
const CustomStrategy = require('passport-custom');
passport.use('ntlm-ad-backend', new CustomStrategy((req, done) => {
let username = req.ntlm.UserName;
AD.findUser(username, (err, profile) => {
if (err) {
console.log(err);
done(err);
}
if (!profile) {
done(new Error(`User ${req.ntlm.UserName} not found in Active Director.`));
} else {
done(null, profile);
}
});
}));
And then,
app.get('/auth', passport.authenticate('ntlm-ad-backend', {
successRedirect: '/',
failureRedirect: '/unsecured'
}));
Note that you will also have to implement serializeUser and deserializeUser.
I'm trying to login a CouchDB User into my express app via a frontend form and store the login in the session. What have so far is the following:
app.js:
var express = require('express');
var couchUser = require('express-user-couchdb');
var session = require('express-session');
var login = require('./routes/login');
var app = express();
app.use(couchUser({
users: 'http://localhost:5984/_users',
request_defaults: {
auth: {
user: 'admin',
pass: 'adminpw'
}
}
}));
app.use(session({ secret: 'secretstring'}));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', login);
and in my login.js:
var express = require('express');
var router = express.Router();
var couchUser = require('express-user-couchdb');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.render('login', {title: 'Login'});
});
router.post('/login', function(req, res) {
// Don't know what to put here
//res.send(req.body.username)
});
module.exports = router;
I don't know how to go on in my login.js route. Any help is appreciated.
Update - Since I couldn't get the code underneath to work because I didn't understand it completely, research lead me to the following solution:
router.post('/', function(req, res) {
var options = {
url: 'http://localhost:5984/_session',
method: 'POST',
json: {
"name": "admin",
"password": "password"
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log('authenticated');
}else{
console.log('not authenticated');
res.redirect('/')
}
});
});
When I do the same request via HttpRequester I get Statuscode 200 and {"ok":true,"name":null,"roles":["_admin"]} .. but via nodejs it won't do it even though it should be the same?!?
To validate user credentials against CouchDB just follow the example from CouchDB documentation.
curl -X POST http://localhost:5984/_session -d 'name=jan&password=apple'
After successful authentication you can keep CouchDB credentials the session storage.
I created a "proof of concept" code which is probably even not correct since i am not nodejs expert. But after some tuning it should work.
var http = require('http');
router.post('/login', function(req, res) {
var session = req.session;
request.post('http://localhost:5984/_session')
.auth(req.data.username, req.data.password, true)
.on('response', function(response) {
if(response.statusCode == 200) {
session.couchSession = req.data.username + ':' + req.data.password;
res.status(200);
res.send();
} else {
res.status(400);
res.send('Wrong credentials');
}
});
});
I'm trying to add basic authorization to an entire site on Express. If a user enters the correct credentials, then I would like the standard landing page to display. If not, then the user should be brought to an "access denied" page. I'm trying to figure out how to alter the basic-auth middleware example to accomplish this:
var http = require('http')
var auth = require('basic-auth')
// Create server
var server = http.createServer(function (req, res) {
var credentials = auth(req)
if (!credentials || credentials.name !== 'john' || credentials.pass !== 'secret') {
res.statusCode = 401
res.setHeader('WWW-Authenticate', 'Basic realm="example"')
res.end('Access denied')
} else {
res.end('Access granted')
}
})
If I use next(); instead of res.end(), I get an undefined error.
var server = http.createServer(function (req, res, next) {
var credentials = auth(req)
if (!credentials || credentials.name !== 'john' || credentials.pass !== 'secret') {
res.statusCode = 401
res.setHeader('WWW-Authenticate', 'Basic realm="example"')
res.end('Access denied')
} else {
next();
}
})
This is what my routes look like:
app.use('/api/things', require('./api/thing'));
// . . .
// All other routes should redirect to the index.html
app.route('/*')
.get(function(req, res) {
res.sendFile(path.resolve(app.get('appPath') + '/index.html'));
});
next is a construction of connect which is a middleware library underlying the Express web server. But you're passing your own handler function to the http server. You should make the http server use the express app to handle requests. Then express's middleware makes it simple.
var http = require('http');
var auth = require('basic-auth');
var app = require('express')();
var server = http.Server(app);
server.listen(3000);
app.get('/', ensureCredentials, function(req, res){
res.sendFile(path.resolve(app.get('appPath') + '/index.html'));
})
app.all('*', function(req, res){
res.redirect('/');
})
function ensureCredentials(req, res, next){
// do logic
if(){
res.status(403).send('Unauthorized')
} else {
next();
}
}
Its important to understand that Express doesn't execute any middlewares after a response is sent with res.send(), res.json(), res.end(), res.redirect(). So in one situation (/ with bad auth), the ensureCredentials function sends a 403 and the app.get('/') handler won't be run. In another situation, the auth checks out, next() is called, and the app.get('/') handler is run.
This is my Express middleware stack:
var server = express()
.use(express.cookieParser())
.use(express.session({secret: 'Secret'}))
.use(express.bodyParser())
.use(function printSession(req, res, next) {
console.log(req.session.user);
next();
})
.use(express.static('./../'));
and here are two routes:
server.post('/setSession', function (req, res) {
req.session.user = 'admin';
}
server.post('/getSession', function (req, res) {
console.log(req.session.user);
}
Now the session management in the route handlers work find. I can set session.user and it will persist for the subsequent requests in the same session, as confirmed by getSession. However, the middleware function printSession always prints undefined.
How can I access the populated session object in the middleware?
This program works fine. Before I access /setSession, the middleware prints after session: undefined. Once I GET /setSession, it prints after session: admin. As long as the browser you are testing with (not curl) stores and sends the session cookies, this will work as expected.
var express = require('express');
var server = express();
server.use(express.cookieParser());
server.use(express.session({secret: 'SEKRET'}));
server.use(function (q,r,n) {console.log('after session:', q.session.user);n();});
server.get('/', function (q,r,n) {r.send("you got slashed");});
server.get('/setSession', function (req, res) {
console.log("logging admin in via /setSession");
req.session.user = 'admin';
res.send("admin logged in");
});
server.listen(3000);
There must be something wrong with your settings. The following example, that is very similar to your code but uses GET instead POST, works fine for me
app.configure(function(){
// ...
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(function(req, res, next) {
console.log(req.session.user + ' from middleware');
next();
});
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
and
app.get('/getSession', function(req, res) {
console.log(req.session.user);
res.send('awesome');
});
app.get('/setSession', function(req, res) {
req.session.user = 'admin';
res.send('done');
});
Now when you do the following everything works as expected
GET /getSession => undefined from middleware, undefined
GET /setSession => undefined from middleware
GET /getSession => admin from middleware, admin