How create cookies in browser with node js - javascript

I have a function authenticate of users in node js, and I'm not using an authentication, passport or other lib, I couldn't understand it well, so I did my own authentication function.
However, my function is only authentic for users, it does not create cookies, I need to create cookies on a "expiration date" node, and that as soon as it waits, it redirects me back to the login route. I want to implement this in this function:
function verify(req,res,username,password){
db.serialize(function (){
const query = 'SELECT * from Users WHERE User = (?) AND Password = (?)'
db.all(query,[username, password],function(err,rows){
if(err) {
console.log(err);
}
if(rows.length == 1){
console.log(rows);
console.log("Correct user");
res.render(__dirname + "/View/Home/index.handlebars");
}
else{
console.log("Incorrecto user!")
res.redirect('/login')
}
});
});
}
This is my route in node js
app.get("/login", (req,res) => {
res.render(__dirname + "/View/Home/login.handlebars");
});
app.post("/",(req,res) => {
const username = req.body.username
const password = req.body.password
verify(req,res,username,password)
});
I need to create a cookie within the verify () function if the user is valid and when the cookie expires the user is redirected to the "/ login" route again

Assuming you're using Express server, you can set cookies using res.cookie(name, value, options). options is an object, and the maxAge property is probably what you want, which is a number is miliseconds before it expires. For example, if the user is valid you could do res.cookie('username', username, {maxAge: 172800000 /* two days */}).
You can access the request's cookies with req.cookies, which is an object of cookie name keys and string values. You can check if the 'username' key exists and is valid, and if not, redirect using res.redirect.
function verify(req,res,username,password){
// Place this block wherever you want it to check for a valid cookie
// Depending on the context when this function is called, that might not be at the start
if(typeof(req.cookies.username) != 'string')
res.redirect('/login');
db.serialize(function (){
const query = 'SELECT * from Users WHERE User = (?) AND Password = (?)'
db.all(query,[username, password],function(err,rows){
if(err) {
console.log(err);
}
if(rows.length == 1){
console.log(rows);
console.log("Correct user");
// Set Cookie
res.cookie('username', username, {maxAge: 172800000 /* two days */});
res.render(__dirname + "/View/Home/index.handlebars");
}
else{
console.log("Incorrecto user!")
res.redirect('/login')
}
});
});
}

Use Keycloak
Download
Offical Keycloak Download Page
Install For Linux/Unix
./bin/standalone.sh
** Install For Windows**
\bin\standalone.bat
Use arg -b to Bind network address (default is 127.0.0.1) like so
./bin/standalone.sh -b 192.168.1.150
Install Keycloak-nodejs-connect
npm install keycloak-connect
Official Node.js Example from Github
Reference: Getting Started Guide

Related

How to start session and destroy session with sessionId in node js

I am using express-session module in node.js for session management. I created session for login and getting session Id But, when I checked with postman it shows always same session Id for every login until until session destroy.
How can I create proper sessions with Id and how can I check whether session is live or not using session Id. Finally how to destroy the session with session using session Id.
what I tried is
var userLogin = function(req,callback){
var sess = req.session;
var data = req.body;
var query = "call userLogin(?,?)";
var table = [data.email,data.pass];
query = Repo.format(query,table);
Repo.execute(query,function(err,result){
if(err){
}else{
sess.email = data.email;
sess.pass = data.pass;
console.log("session ID is ",req.sessionID);
if(req.sessionID){
console.log("session is in");
}
else{
console.log("session is out");
}
sess.destroy();
console.log(req.sessionID);
if(req.sessionID){
console.log("aft session is in");
}
else{
console.log("aft session is out");
}
}
outPut(callback,err,result);
});
}
Thank you.

Http authorization with node.js

My former server.js is like:
After running the server I could see my index.html
var connect = require('connect');
var serveStatic = require('serve-static');
connect().use(serveStatic(__dirname)).listen(5000, '192.168.xx.xx', function(){
console.log('Server running on 5000');
});
I want to create http login and password to secure the website, so I found online the information of http module: if I put right login and password, I could see congratulations message:
var http = require('http');
var server = http.createServer(function(req, res) {
// console.log(req); // debug dump the request
// If they pass in a basic auth credential it'll be in a header called "Authorization" (note NodeJS lowercases the names of headers in its request object)
var auth = req.headers['authorization']; // auth is in base64(username:password) so we need to decode the base64
console.log("Authorization Header is: ", auth);
if(!auth) { // No Authorization header was passed in so it's the first time the browser hit us
// Sending a 401 will require authentication, we need to send the 'WWW-Authenticate' to tell them the sort of authentication to use
// Basic auth is quite literally the easiest and least secure, it simply gives back base64( username + ":" + password ) from the browser
res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
res.end('<html><body>Need authorization</body></html>');
}
else if(auth) { // The Authorization was passed in so now we validate it
var tmp = auth.split(' '); // Split on a space, the original auth looks like "Basic Y2hhcmxlczoxMjM0NQ==" and we need the 2nd part
var buf = new Buffer(tmp[1], 'base64'); // create a buffer and tell it the data coming in is base64
var plain_auth = buf.toString(); // read it back out as a string
console.log("Decoded Authorization ", plain_auth);
// At this point plain_auth = "username:password"
var creds = plain_auth.split(':'); // split on a ':'
var username = creds[0];
var password = creds[1];
if((username == 'admin') && (password == 'admin')) { // Is the username/password correct?
res.statusCode = 200; // OK
res.end('<html><body>Congratulations, feel free to explre!</body></html>');
}
else {
res.statusCode = 401; // Force them to retry authentication
res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
// res.statusCode = 403; // or alternatively just reject them altogether with a 403 Forbidden
res.end('<html><body>You shall not pass</body></html>');
}
}
});
server.listen(5000, function() { console.log("Server Listening on http://localhost:5000/"); });
I am new to nodejs, I want to know how to combine this 2 js? In order to realize my function of adding authorization to my web.
Could I do something to show my index instead of showing congratulation message after putting the login and password?
Thanks a lot.
In order to show HTML page instead of congratulation message, you can follow these steps:
Get request path by req.url, such as / or /introduction.html.
According to the above path, read the corresponding HTML file in server disk, using fs.readFile().
Return HTML file content to browser if the read is successful. Otherwise, return 404 error page.
Here is some example code for above steps:
if((username == 'admin') && (password == 'admin')) { // Is the username/password correct?
res.statusCode = 200; // OK
// res.end('<html><body>Congratulations, feel free to explre!</body></html>');
var requestURL = req.url; // e.g. / or /a or /a.html
var requestFilePath = getFilePathFromRequestURL(requestURL); // you need to implement this logic yourself, such as "/" mapping to "./index.html"
fs.readFile(requestFilePath, function(error, data) {
if (error) {
res.statusCode = 404;
res.write('File not found.');
} else {
res.statusCode = 200;
res.write(data);
}
res.end();
});
}
However, unless you want to write some low-level node.js code to better understand this language, I highly recommend using node.js web framework such as Express. Serve HTTP request using low-level node.js would be tedious, especially in production code.
Also, please note that using WWW-Authenticate Basic for authentication is neither secure nor user-friendly. You need some other way to implement authentication, such as JSON Web Tokens

Single object of socket IO

I am trying to create an application based on socket. Looking at the console it can be said that the client to trying to socket server twice; which should not be allowed.
Is there any way to stop that?
If have modular javascript file where multiple script want to access same socket connection how is that possible?
<!DOCTYPE html>
<html>
<head>
<title>socket</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
</head>
<body>
<script type="text/javascript">
$(function(){
var socket = io();
console.log(typeof socket); // object
var socket1 = io();
console.log(socket === socket1); // false
})
</script>
</body>
</html>
Don't connect the client to socket twice....
A global variable will allow you to access the socket from all your script files
Eg)
//you can access this variable from all your scripts
var socket;
$(function(){
socket = io();
console.log(typeof socket);
})
Note that in javascript polluting the global scope with variables and functions is considered bad practice, but that's for another post.
The obvious suggestion is to stop having your client connect twice.
But, if you're trying to prevent multiple connections on the server and you really don't want any end user to be able to use more than one window at a time to your web site, then you can prevent another connection once there is already a connection.
The key would be to identify each browser with some sort of unique cookie (user ID or uniquely generated ID number). You can then implement socket.io authentication that keeps track of which user IDs already have a connection and if a connection is already live, then subsequent attempts to connect will fail the authentication step and will be disconnected.
Supposed you have a cookie set for each browser that's called userId. Then, here's a sample app that makes sure the userId cookie is present and then uses it to deny more than one socket.io connection:
const express = require('express');
const app = express();
const cookieParser = require('cookie-parser');
const cookie = require('cookie');
app.use(cookieParser());
let userIdCntr = 1;
const tenDays = 1000 * 3600 * 24 * 10;
app.use(function(req, res, next) {
// make sure there's always a userId cookie
if (!req.cookies || !req.cookies.userId) {
// coin unique user ID which consists of increasing counter and current time
let userId = userIdCntr++ + "_" + Date.now();
console.log("coining userId: " + userId);
res.cookie('userId', userId, { maxAge: Date.now() + tenDays , httpOnly: true });
}
next();
});
app.get('/test.html', function (req, res) {
console.log('Cookies: ', req.cookies)
res.sendFile( __dirname + "/" + "test.html" );
});
const server = app.listen(80);
const io = require('socket.io')(server);
// which users are currently connected
var users = new Set();
// make sure cookie is parsed
io.use(function(socket, next) {
if (!socket.handshake.headers.cookieParsed) {
socket.handshake.headers.cookieParsed = cookie.parse(socket.handshake.headers.cookie || "");
}
next();
});
// now do auth to fail duplicate connections
io.use(function(socket, next) {
console.log("io.use() - auth");
// if no userId present, fail the auth
let userId = socket.handshake.headers.cookieParsed.userId;
if (!userId) {
next(new Error('Authentication error - no userId'));
return;
}
// if already logged in
if (users.has(userId)) {
console.log("Failing user " + userId);
next(new Error('Authentication error - duplicate connection for this userId'));
return;
} else {
console.log("adding user " + userId);
users.add(userId);
}
next();
});
io.on('connection', function(socket) {
console.log("socket.io connection cookies: ", socket.handshake.headers.cookieParsed);
socket.on('disconnect', function() {
console.log("socket.io disconnect");
let userId = socket.handshake.headers.cookieParsed.userId;
users.delete(userId);
});
// test message just to see if we're connected
socket.on("buttonSend", function(data) {
console.log("buttonSend: ", data);
});
});
P.S. You really have to think through the situation where a user with more than one computer (like home/work) leaves one computer on and open to your page and thus connected via socket.io and then attempts to user your site from the other computer. If you refused the second connection, this will refuse to allow them access from their second computer if the first computer happened to be left open and on.

Connect signed cookie parsing falsy

I'm having problems while trying to parse back signed cookies in express/connect application.
io.set('authorization', function (handshakeData, callback) {
if(handshakeData.headers.cookie) {
var signedCookies = cookie.parse(decodeURIComponent(handshakeData.headers.cookie));
handshakeData.cookie = connect.utils.parseSignedCookies(signedCookies, secret);
} else {
return accept('No cookie transmitted', false);
}
callback(null, true); // error first callback style
});
What happens is call to connect.utils.parseSignedCookies returns empty object. I looked into source for parse function and found out that it calls unsign method which gets a substring of encoded value and then tries to sign it again with the same secret and compare the results to verify that its the same value encoded and for some reasons it fails and values does not match. I don't know what I'm doing wrong, why those values differs and why I'm unable to get correct session ID.
My app initialization code looks like this:
app.use(express.cookieParser(secret));
app.use(express.session({
key: 'sessionID',
secret: secret,
maxAge: new Date(Date.now() + 3600000),
store: new RedisStore({
client: redisClient
})
}));
Please help and point what I'm doing wrong here. Thank you
The cookie parser is a middleware, so we have to use it like one. It will actually populate the object that you pass to it. This is how you would want to be using the parser:
// we need to use the same secret for Socket.IO and Express
var parseCookie = express.cookieParser(secret);
io.set('authorization', function(handshake, callback) {
if (handshake.headers.cookie) {
// pass a req, res, and next as if it were middleware
parseCookie(handshake, null, function(err) {
// use handshake.signedCookies, since the
// cookie parser has populated it
});
} else {
return accept('No session.', false);
}
callback(null, true);
});
The cookie parser API changed and this is what it looks like now:
module.exports = function cookieParser(secret) {
return function cookieParser(req, res, next) {
if (req.cookies) return next();
var cookies = req.headers.cookie;
req.secret = secret;
req.cookies = {};
req.signedCookies = {};
if (cookies) {
try {
req.cookies = cookie.parse(cookies);
if (secret) {
req.signedCookies = utils.parseSignedCookies(req.cookies, secret);
req.signedCookies = utils.parseJSONCookies(req.signedCookies);
}
req.cookies = utils.parseJSONCookies(req.cookies);
} catch (err) {
err.status = 400;
return next(err);
}
}
next();
};
};
So what we're doing is passing handshake as a request object, and the parser will read the headers.cookie property. Then, the cookies will be parsed, and put into req.signedCookies. Since we passed handshake as req, the cookies are now in handshake.signedCookies. Note that the cookies are only signed because you passed a secret to the parser.
I was having problems left and right with cookies/sessions/socket.io etc. It was finally #vytautas comment that helped me. In case anyone sees this, please make sure you're connecting to the correct host, whether you have it setup as localhost or an IP address or what have you. Otherwise you won't be able to parse your incoming cookies.
(Seems kind of obvious in hindsight.)

Expressjs / Node.js - res.redirect() not loading page

I have a page with a route GET /team which is loading a list of teams, and DEL /team which is deleting a team from /team/:key. So you navigate to a team's profile page and delete them from there, on deletion it should redirect you to the /team page. I have put logs into the console and it is successfully deleting the team and wierdly, it says it is loading /team but the browser does not load this. I have put my code below, any ideas?
Routes:
app.get('/team'/*, lim("Must be logged in to see teams")*/, getAllTeams, function(req, res){
util.log('Serving request for url [GET] ' + req.route.path);
// Pass it the list of all Teams
res.render('team', {'teamsList' : req.teamsList} );
});
app.get('/team/:key', function(req, res) {
util.log('Serving request for url [GET] ' + req.route.path);
Team.findByKey(req.params.key, function(err, teamData){
if(!err && teamData){
teamData = teamData;
res.render('teamDetails', { 'teamData' : teamData } );
} else {
util.log('Error in fetching Team by key : ' + req.params.key);
res.json({
'retStatus' : 'failure',
'msg' : 'Error in fetching Team by key ' + req.params.key
});
}
});
});
/**
* DEL /team/:key
* Delete Team by key
*/
app.del('/team/:key', getAllTeams, function(req, res) {
util.log('Serving request for url [DEL] ' + req.route.path);
Team.remove({key : req.params.key}, function(err){
var message = '';
var retStatus = '';
if (!err) {
util.log('Successfully deleting Team with key: ' + req.params.key);
message = 'Successfully deleting Team with key: ' + req.params.key;
retStatus = 'Success';
res.redirect('/team');
} else {
util.log('Error deleting Team with key: ' + req.params.key + 'Error: ' + util.inspect(err));
res.json({
'retStatus' : 'failure',
'msg' : 'Error in fetching Team with key ' + req.params.key
});
}
});
});
JavaScript + HTML template:
button#teamDelete.btn.btn-danger.btn-mini(type="submit", value="Delete Team") Delete
script(type='text/javascript')
$('#teamDelete').live('click',function(){
var teamId = #{teamData.key};
$.post('/team/' + teamId, { _method : 'delete' }, function(response) {
console.log(response);
if(response.retStatus === 'Success') {
if('/team' && '/team' !== "") {
window.location = '/team';
}
}
});
});
console logs:
10 Mar 11:52:01 - Serving request for url [GET] /team
10 Mar 11:52:02 - Serving request for url [GET] /team/:key
10 Mar 11:52:03 - Serving request for url [DEL] /team/:key
10 Mar 11:52:03 - Successfully deleting Team with key: 1362855941128
10 Mar 11:52:03 - Serving request for url [GET] /team
getAllTeams:
var getAllTeams = function(req, res, next){
Team.getAll(function(err, teamsList){
if(!err && teamsList){
req.teamsList = teamsList;
return next();
}
});
};
Team.getAll (Team schema)
Team.statics.getAll = function(cb){
var query = this.find({});
query.sort({key : -1});
return query.exec(cb);
};
Your request is POST ($.post) and you route is app.del, so it never gets to res.redirect inside app.del route.
Why don't you use app.post?
Updated:
Assuming $.post sends HTTP DEL request here what is happening: server sends 302 response with no data but browser never sends another request to GET route as server instructs it (or does jQuery handle redirects too? Not sure). res.redirect() is actual HTTP response not some internal server-side instruction to re-route the request to another route like you can do in ASP.NET (and which is wrong actually)... Route is designed to receive request, reply with the response and forget about it. You need to separate routes from actual functions processing them, then you will be able to call that function instead of sending redirect.
Code suggestions
In app.del('/team/:key' ...
...
retStatus = 'Success';
// res.redirect('/team');
res.send({
retStatus : retStatus,
redirectTo: '/team',
msg : 'Just go there please' // this should help
});
...
Client-side in $.post('/team/' ...
...
$.post('/team/' + teamId, { _method : 'delete' }, function(response) {
console.log(response);
if(response.retStatus === 'Success') {
// not sure what did you mean by ('/team' && '/team' !== "")
// if('/team' && '/team' !== "") {
if (response.redirectTo && response.msg == 'Just go there please') {
window.location = response.redirectTo;
}
}
});
...
Not sure it will work though because I don't understand what your getAllTeams does and why you store teamList in req. If you want to store in session, than assuming the middleware is correctly configured you need to use req.session. If you need to store it only within request and your getAllTeams prepares this list of teams it is better to store in res.locals (like res.locals.teamList).
And make sure your getAllTeams calls next. So basically your getAllTeams should look like this:
function getAllTeams (req, res, next) {
res.locals.teamList = [/* whatever */];
next();
}
And then you can use res.locals.teamList in your route handler instead of req.teamList.
res.render('team', {teamsList : res.locals.teamsList} );
And 'team' template also can have a problem...
Express advice :)
Also the way you use Express makes it very difficult to extend/manage application. I don't remember where exactly, but somewhere in docs they write that Express is supposed to be used as the foundation for your application framework, not as a complete framework like most PHP frameworks are. It gives you a lot of power and flexibility, but also makes it necessary to think about your application architecture well in advance.
The most powerful feature of express is that you can have any route handled by many route-specific handlers/middlewares passing control to each other via next(). I have a static table that defines which handlers are used on each route allowing to see the whole application with 30 or so routes on one page. And this table is used to assemble the routing dynamically when the application starts. It leads to a lot of flexibility, manageability (I can move/copy-paste handlers from route to route - each handler is represented as a single word) and code re-use. I also use the same hash of routes definition in the client for client-side routing.
For a quick workaround, just add the redirect url to the response and on the client side do:
if (redirectUrl && redirectUrl !== "")
window.location = redirectUrl;

Categories