I can't access req.session variables in other post requests - javascript

I am developing an apt management app.
Basically, if a user is a resident, they get to see their apt fee payment data.
If the user is from apt management, they select one of the 5 db update options from the apt mgmt menu page by clicking one of the submit buttons numbered from 1 to 5.
I am trying to make my code session-based so I am attaching my own variables to req.session object as req.session.loggedin, req.session.userid and req.session.userpwd.
I authenticate username and userpwd inputs from login page in the first post request to '/server' and if they match in db then I set req.session.loggedin to true.
I was hoping that I would be able to use the req.session.loggedin and req.session.username variables in the second request to '/mgtmenupg' and other requests but unfortunately it doesn’t work because I get undefined error.
At the moment I can’t progress any further. What do I have to do to able able to access req.session.loggedin and req.session.username variables in other requests?
Any help will be appreciated.
Attached is my minimal reproducable examples of js code.
var express = require('express'); // Import Express package
var session = require('client-sessions');
//var session = require('express-session');
var bodyParser = require('body-parser'); // Import body-parser module to parse incoming requests
var cookieParser = require('cookie-parser');
var path = require('path'); //import path module.
var app = express(); // Create an Express app variable so that we can use Express in anywhere.
var router = express.Router();
var cors = require('cors'); //import cors from "cors". CORS allows frontend and backend to share data because they are on different servers.
var port = 3000; //Set port to 3000. This is where our backend server will be.
var mysql = require('mysql');
var alert = require('alert');
const { config } = require('process');
//var { response } = require('express');
var con = mysql.createConnection({ // Create connection object.
host: 'localhost',
user: 'root',
password: 'hsAdmin',
database: 'havuzsDB'
});
//const { request } = require('http');
// Below, we use the imported modules in our Express app.
app.use(express.json() ); // use Express module body-parser to parse JSON-encoded request bodies
app.use(express.urlencoded({extended: true})); // use Express module body-parser to parse URL-encoded request bodies
app.use(cookieParser());
// Use the sessions package to determine if user is logged-in.
app.use(session({
cookieName: 'session',
secret: 'top99secret',
duration: 30 * 60 * 1000,
activeDuration: 5 * 60 * 1000,
httpOnly: true,
secure: true,
ephemeral: true
//resave: true,
//saveUninitialized: true
}));
app.use(cors());
// Set up view engine.
app.engine('html',require('ejs').renderFile);
app.set('view engine', 'ejs');
//app.set('views', path.join(_dirname, 'views'));
// Start your server on a specified port and listen for http request on that port.
// app.listen() is the function that starts a port and host, in our case the localhost for the connections
// to listen to incoming requests from a client.
app.listen(port, () => {
alert("server is running at http://127.0.0.1:", port); //Show server url at console. Use this url in <script> tag of your html code.
});
/* You can use this to check if your server is working.
app.get('/', (req, res)=>{
res.send("Welcome to my server");
}); */
// Connect to havuzsDB database.
con.connect(function(err) {
if (err) {
throw err;
alert("DB Connection failed");
}
else
alert("DB Connected!");
});
// Route to send the local image file to be used as app homepage background, to the client.
app.get('/havuzlusite-img.jpg', function(req, res) {
res.sendFile("D:/Behrans-files/Web-projects/havuzlusite/havuzlusite-img.jpg");
});
// Route to send home page file to the client.
app.get('/', function(req, res) {
res.sendFile("D:/Behrans-files/Web-projects/havuzlusite/homepg.html");
});
// Route to send the login form to the client.
app.get('/loginpg', function(req, res) { //Send login page file to the client.
res.sendFile("D:/Behrans-files/Web-projects/havuzlusite/loginpg.html");
});
//Route to receive and authenticate user login data.
app.post('/server', (req, res) => {
req.session.username = req.body.isim; // save username input in a local variable.
req.session.userpwd = req.body.sifre; // save user pwd in a local variable.
if (req.session.username && req.session.userpwd) { //Check if user has entered name and password in the login form.
con.query('SELECT * FROM havuzs_sakinleri WHERE isim = ? AND sifre = ?', [req.session.username, req.session.userpwd], function(err, rows) {
if (rows.length > 0) {
req.session.loggedin = true;
req.session.rows = rows;
} else {
return alert('İsim ve şifre veri tabanında bulunamadı. Lütfen geçerli bir isim/şifre girin!');
//return res.render('loginpg');
}
res.end();
})
} else {
return res.send('Lütfen isim ve şifre giriniz!');
res.end();
}
//console.log('loggedin:', req.session.loggedin, 'username: ', username);
//If user is a resident, display resident data.
if (req.session.loggedin && req.session.username !== 'Yonetim') {
if (req.session.rows) { // If user name/pwd match db,
var rows = req.session.rows;
return res.render('userdatapg', {rows}); // Display resident data.
res.end;
}
};
//If user is an authorized building management team member, display management menu.
if (req.session.loggedin && req.session.username == 'Yonetim') {
return res.render('mgtmenupg'); //Display db update menu page.
res.end();
}
});
// Determine which button is clicked.
app.post('/mgtmenupg/:btnno', (req, res) => {
// Route to handle apt fee payment - If button#1 is clicked.
if (req.params.btnno == 1) {
res.render('userpmtpg'); //Display user apt fee payment page.
app.post('/userpmtpg', (req, res) => { //Post request to access payment month and payment amount inputs from user.
var username = req.body.username;
var pmtmnth = req.body.pmt_mnth;
var pmtamt = req.body.pmt_amt;
queryusername(username, function(response) { //Pass username and call function to see if the user is in db.
if (response == 'Found') { //If response has no error message, call function to update user payment data in db.
updateUsrPmtData(username, pmtmnth, pmtamt, function(response) { //Call function to update user apt fee payment data in db.
return alert(response); //Display db update status message from called function.
});
} else if (response == 'Not found')
res.send('İsim veri tabanında bulunamadı. Ana sayfaya dönmek için lütfen Ana sayfa butonuna tıklayınız!'); //If response has error message, display error message.
else
res.send('Site sakini ismi veri tabanında aranırken sorun oluştu.');
})
res.render('mgtmenupg');
res.end();
})
}
// Route to handle deletion of existing resident user - If button#2 is clicked.
if (req.params.btnno == 2) {
res.render('deluserpg');
app.post('/deluserpg', (req,res) => {
var username = req.body.username;
queryusername(username, function(response) { //Pass username and call function to see if the user is in db.
if (response == 'Found') { //If response has no error message, it means user is in db, call function to delete it.
deleteUser(username, function(response) { // Pass username input data as parameter to call deleteuser function.
return alert(response); //Display db delete status message from called function.
res.render('mgtmenupg');
})
} else if (response == 'Not found') {
return alert('İsim veri tabanında bulunamadı. Lütfen sistemde mevcut bir isim girin.'); //If response has error message, display error message.
return res.render('deluserpg');
} else
return res.send('Site sakini ismi veri tabanında aranırken sorun oluştu.');
})
res.end();
})
};

Related

How to call a route at a particular time

I have a MERN stack Library Management System website.
In my app currently for admin i have given a Notify button to send emails to all user that have any books due in the library. For this an array of defaulty user gets passed as a req body to send emails. Admin gets this list of users from database on initial render of that particular component.
But i want to automate sending of emails and want my server to trigger automatic emails at 10:00 am to all the users who have due books.
On Notify button click my notifyBookDefaulties controller gets triggered.
I tried to use a setTimeout and a timer as well to call my route at 10:00 am and trigger emails but i am not able to get desired output.
Below i my notifyBookDefaulties controller:
const notifyBookDefaulties = asyncHandler(async (req, res) => {
const admin = await Auth.findById(req.user.id);
// to check if user exists by that id in the databse
// and that user is a admin (got by token)
if (!admin && admin.admin !== true) {
res.status(401);
throw new Error("Not Authorized");
}
const { users, bookID, title } = req.body; // here users is the list of user id's
let emails = "";
// to get email of each user from their user id
for (let user of users) {
try {
const defaulty = await Auth.findById(user);
emails += defaulty.email + ",";
} catch (error) {
res.status(400);
throw new Error(error);
}
}
// to get comma separated list of emails
const emailList = emails.slice(0, -1).toString();
// try block tries to send email and catch block catches any error if occured
try {
var transporter = nodemailer.createTransport({
service: process.env.SERVICE,
auth: {
user: process.env.USER,
pass: process.env.PASS,
},
});
var mailOptions = {
from: process.env.USER,
to: emailList,
subject: "Return Book",
html: `<!DOCTYPE html><html lang="en"><body>This is to remind you that the book titled ${title} and ID ${bookID} issued by you is due.</body></html>`,
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
res.status(400).json({ msg: error });
} else {
res.status(200).json({ msg: "E-Mail Successfully sent" });
}
});
} catch (error) {
console.log(error);
res.status(500).json({ msg: error });
}
});
Below is my server.js:
require("dotenv").config();
const express = require("express");
const { errorHandler } = require("./middleware/errorMiddleware");
const connectDB = require("./config/db");
const cors = require("cors");
const port = process.env.PORT || 5000;
connectDB();
const app = express();
const corsOptions = {
origin: 'http://localhost:3000',
optionsSuccessStatus: 204
};
app.use(cors(corsOptions))
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/api/admin", require("./routes/adminRoutes"));
app.use("/api/user", require("./routes/userRoutes"));
app.use("/api/actions", require("./routes/authRoute"));
app.use(errorHandler);
app.listen(port, () => {
console.log(`Running on ${port}`);
});
My controller gets called for below route:
router.post("/notify", protect, notifyBookDefaulties);
and the url is:
http://localhost:5000/api/admin/notify
Note: here i have not included my function which fetches the list of user id's, of users that have due books. To fetch defaulting users i have a separate controller and i will merge that into this controller once i get the logic to send mails at 10:00 am.
If there is any other way to implement this i would like to know. If any more clarity needed do tell. Thanks in advance.
Sounds like a cron job, check this package https://www.npmjs.com/package/node-cron

Rendering a template/view in client side javascript

I am new to node and making a simple login page - The client-side javascript takes the values from input then makes a post request to a server which has a database containing all the user accounts. In the server this info is checked :
-If details are correct they should be taken to a new page which has dynamic content in (their username)
-If the details are incorrect then the main page should not change - I just want an element to be added saying "Incorrect password, try again"
This worked fine when i was making the post request directly from the form but have decided to change this so that i can display "incorrect password, try again" on the sign-in page.
My client-side javascript
"use strict"
document.querySelector("button").addEventListener("click",submit)
async function submit(e){
e.preventDefault();
let username=document.querySelector("#username").value
let password=document.querySelector("#password").value
let options = {
headers:{
"Content-Type" : "application/json"
},
method: "POST",
body: JSON.stringify({username,password})
}
let response = await fetch("/api",options)
let responseData = await response.json()
if(responseData.status == "fail"){
console.log("show the fail message");
}
}
My server-side js:
"use strict"
//Installing express
let express = require(`express`)
let app = express()
app.use(express.json())
var bodyParser = require('body-parser')
var urlencodedParser = bodyParser.urlencoded({ extended: false })
let ejs = require('ejs');
app.set("view engine","ejs")
//running the server
app.listen(3000,()=>{
console.log("server is running boi");
})
//Middleware to load the static content
app.use(express.static('public'))
//Database stuff
let Datastore = require('nedb')
let db = new Datastore({ filename: 'database.db' });
db.loadDatabase()
//Handler for any post requests made from the form
app.post('/api', urlencodedParser, function (req, res) {
let user = req.body.username
//querying the db
db.find({username:user},(err,docs)=>{
if(docs[0]){
if(docs[0].password == req.body.password){
console.log("You have logged in!");
res.send({status:"success"})
}else{
console.log("incorrect password")
res.send({status:"fail"})
}
}else{
console.log("incorrect username");
res.send({status:"fail"})
}
})
})
If the user passes the details and the details are correct then I want a template to be rendered with their name on (I use EJS), How can I do this from the client-side and if I can not, what can I do?
As I can see, you are using EJS but not rendering anything. Instead, you are sending a JSON response to your client. Now, from your client you can do this:
Client code:
let responseData = await response.json()
if(responseData.status == "fail"){
alert('Failed to login');
// You can do DOM manipulation here. Like: show a message to user
} else {
// Login success. Do something here
alert('Login success')
}
UPDATE: Using EJS
app.post('/api', urlencodedParser, function (req, res) {
let user = req.body.username;
db.find({username:user},(err,docs)=>{
if(docs[0]) {
res.render('template', {user: docs[0]})
} else {
res.render('template', {user: null})
}
})
}
In your EJS:
<% if (user === null) { %>
<h1>Login failed</h1>
<% } else { %>
<h1>Login success</h1>
<% } %>

How to set the token to local storage or cookies so that i can allow user to access certain web pages

I am trying to build an authentication system so, i used node , mysql,express for that so now i am simply saving and checking user exist in database can access but now i added JWT to it, so now i want this JWT token to store in localstorage or in cookies so, can someone guide me how can i do so
this is my authentication controller.js
var Cryptr = require('cryptr');
cryptr = new Cryptr('myTotalySecretKey');
var express = require('express');
const ap = express();
var jwt = require('jsonwebtoken');
var connection = require('./../config');
module.exports.authenticate = function (req, res) {
var email = req.body.email;
var password = req.body.password;
connection.query('SELECT * FROM users WHERE email = ?', [email], function (error, results, fields) {
if (error) {
res.json({
status: false,
message: 'there are some error with query'
});
} else {
if (results.length > 0) {
decryptedString = cryptr.decrypt(results[0].password);
if (password == decryptedString) {
jwt.sign({ email, password },
'secretkey',
{ expiresIn: '10days' },
(err, token) => {
console.log('token:' + token);
module.exports = token;
console.log(token);
res.redirect('/home.html');
}
);
} else {
res.redirect('/login.html');
console.log("Wrong Input");
}
}
else {
res.redirect('/login.html');
}
}
});
};
now i want to pass the token value to the local-storage or cookies so that i can restrict someone from acessing a page, i am reallly new to node js so any help would be appriciated
First I should notify you that do not put any secret things like password in jwt payload because the values of the payload could be accessed easily, you can try to copy paste a jwt in jwt.io site and see the payload.
set jwt in cookie like below, this will use express cookie method that does set Http Set-Cookie header:
res.cookie('jwt', generated_cookie)
.redirect('/home.html');
Also if you want to use localStorage you can set jwt in header and then in your code get the jwt from the header of login request and save it in localStorage and after that you should pass it as header in all other request, but this approach is a better solution for api calls like when you use react or vue ...
res.set({x-token: generated_token});
// In your code get
// get token from response
localStorage.setItem('token', token);
// now whenever calling api pass token as header
I show you one solution using jwt token, you choose another way:
Back-end file e.g. api.js
let jwt = require('jsonwebtoken')
let secret = 'yourSecret'; //secret key necessary to encode token
let Cryptr = require('cryptr');
let cryptr = new Cryptr('myTotalySecretKey');
module.exports = function(router,upload) {
function tokenAuth(req, res, next){
let token = req.body.token || req.body.query || req.headers['x-access-token']
if(token){
jwt.verify(token, secret, function(err,decoded){
if(err){
res.json({ authenticated: false, message:'Invalid token'})
} else {
req.decoded = decoded;
next()
}
})
} else {
res.json({success:false, message:'No token provided'});
}
}
router.post('/authenticate', function(req, res){
connection.query('SELECT * FROM users WHERE email = ?', [email], function (error, results, fields){
if(error) {
res.json({ success:false, message: err })
}
if(!results.length){
res.json({success:false, message:'User no found'})
} else if (results.length>0){
if(!req.body.password){
res.json({success:false, message:'Password was not provided'});
} else {
var validPassword = cryptr.decrypt(results[0].password);
if(validPassword === req.body.password){
res.json({success:false, message:'Incorrect password'})
} else {
var token = jwt.sign({username: results[0].username, email: results[0].email}, secret, {expiresIn: '24h'})
res.json({success:true, message:'You have logged in correctly!', token: token })
}
}
}
})
})
//If you want create a route for authenticated users for example comment posts, you can use our `tokenAuth function`
router.post('/post/comment',tokenAuth,function(req,res){
//access only for authenticated users
}
return router
}
This tokenAuth function we'll be use in paths restricted to authenticated users
server file e.g. server.js
const express = require('express');
const app = express();
const port = process.env.PORT || 80;
const http = require('http').Server(app);
const routes = require(path_to_api.js)(router);
app.use('/myApi', routes)
//***Here you should implement more details about your project such as routes, body parsers and other middlewares*****//
//Connect to your database
http.listen(port, ()=> console.log(`Server running on ${port}`))
Front-end file e.g. controller.js
function(login){
return fetch('/myApi/authenticate',{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(login)
}).then(result=>result.json()).then(data=> window.localStorage.setItem('token', data.token))
}
//`login` argument should be an object and should be like {username: 'user username', password: 'user password'}
In order to make a user store cookies, you can use the Set-Cookie header. From MDN:
Set-Cookie: <cookie-name>=<cookie-value>
In order to pass a header using Express, you can use res.set(), e.g. res.set("Set-Cookie", "Token=" + token). I also suggest you use the HttpOnly cookie directive, since it seems from your post that you don't access this token directly via Javascript and you simply want to check it when the client requests a webpage: res.set("Set-Cookie", "Token=" + token + "; HttpOnly").
The client will send the Cookie header to you when it requests a resource. You can check this header using req.header('Cookie'), and the output will be "Token=<token>" if the user is authenticated. You can then check this token for authenticity.

How to set headers for json web token in expressjs?

Hello I am working on mock authentication in nodeJs using express framework.I am using passport-jwt and jasonwebtoken for authentication. I created api and working well on postman.But I stuck on front end side I am not able to use protected api's on front end side.In postman i send token using headers and it works well.But it does not work on front end side.How to send token and verify from front end side??
My code is:
app.post("/login", function(req, res) {
if(req.body.name && req.body.password){
var name = req.body.name;
var password = req.body.password;
}
var user = users[_.findIndex(users, {name: name})];
if( ! user ){
res.status(401).json({message:"no such user found"});
}
if(user.password === req.body.password) {
var payload = {id: user.id};
var token = jwt.sign(payload, jwtOptions.secretOrKey);
res.json({message: "ok", token: token});
} else {
res.status(401).json({message:"passwords did not match"});
}
});
and if token is valid this post method should redirect to this page
app.get("/secret", passport.authenticate('jwt', { session: false }), function(req, res){
res.json("Success! You can not see this without a token");
});
npm install cookie-parser
var cookieParser = require('cookie-parser')
app.use(cookieParser())
app.use(function (req, res, next) {
var cookie = req.cookies.jwtToken;
if (!cookie) {
res.cookie('jwtToken', theJwtTokenValue,
{ maxAge: 900000, httpOnly: true });
} else {
console.log('let's check that this is a valid cookie');
// send cookie along to the validation functions...
}
next();
});

Loopback IO OAuth not working

I am trying to get a https loopback server up and running protected by OAuth. I am using the loopback gateway sample project as a reference. But for some reason I can't get the OAuth piece to work. What I mean is, even after adding in the OAuth bits and pieces, the APIs don't seem to be protected. I get a response back even if there is no token in my request. This is what my server.js looks like
var loopback = require('loopback');
var boot = require('loopback-boot');
var https = require('https');
var path = require('path');
var httpsRedirect = require('./middleware/https-redirect');
var site = require('./site');
var sslConfig = require('./ssl-config');
var options = {
key: sslConfig.privateKey,
cert: sslConfig.certificate
};
var app = module.exports = loopback();
// Set up the /favicon.ico
app.middleware('initial', loopback.favicon());
// request pre-processing middleware
app.middleware('initial', loopback.compress());
app.middleware('session', loopback.session({ saveUninitialized: true,
resave: true, secret: 'keyboard cat' }));
// -- Add your pre-processing middleware here --
// boot scripts mount components like REST API
boot(app, __dirname);
// Redirect http requests to https
var httpsPort = app.get('https-port');
app.middleware('routes', httpsRedirect({httpsPort: httpsPort}));
var oauth2 = require('loopback-component-oauth2')(
app, {
// Data source for oAuth2 metadata persistence
dataSource: app.dataSources.pg,
loginPage: '/login', // The login page url
loginPath: '/login' // The login processing url
});
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Set up login/logout forms
app.get('/login', site.loginForm);
app.get('/logout', site.logout);
app.get('/account', site.account);
app.get('/callback', site.callbackPage);
var auth = oauth2.authenticate({session: false, scope: 'demo'});
app.use(['/protected', '/api', '/me', '/_internal'], auth);
app.get('/me', function(req, res) {
// req.authInfo is set using the `info` argument supplied by
// `BearerStrategy`. It is typically used to indicate scope of the token,
// and used in access control checks. For illustrative purposes, this
// example simply returns the scope in the response.
res.json({ 'user_id': req.user.id, name: req.user.username,
accessToken: req.authInfo.accessToken });
});
signupTestUserAndApp();
//var rateLimiting = require('./middleware/rate-limiting');
//app.middleware('routes:after', rateLimiting({limit: 100, interval: 60000}));
//var proxy = require('./middleware/proxy');
//var proxyOptions = require('./middleware/proxy/config.json');
//app.middleware('routes:after', proxy(proxyOptions));
app.middleware('files',
loopback.static(path.join(__dirname, '../client/public')));
app.middleware('files', '/admin',
loopback.static(path.join(__dirname, '../client/admin')));
// Requests that get this far won't be handled
// by any middleware. Convert them into a 404 error
// that will be handled later down the chain.
app.middleware('final', loopback.urlNotFound());
// The ultimate error handler.
app.middleware('final', loopback.errorHandler());
app.start = function(httpOnly) {
if(httpOnly === undefined) {
httpOnly = process.env.HTTP;
}
server = https.createServer(options, app);
server.listen(app.get('port'), function() {
var baseUrl = (httpOnly? 'http://' : 'https://') + app.get('host') + ':' + app.get('port');
app.emit('started', baseUrl);
console.log('LoopBack server listening # %s%s', baseUrl, '/');
});
return server;};
// start the server if `$ node server.js`
if (require.main === module) {
app.start();
}
function signupTestUserAndApp() {
// Create a dummy user and client app
app.models.User.create({username: 'bob',
password: 'secret',
email: 'foo#bar.com'}, function(err, user) {
if (!err) {
console.log('User registered: username=%s password=%s',
user.username, 'secret');
}
// Hack to set the app id to a fixed value so that we don't have to change
// the client settings
app.models.Application.beforeSave = function(next) {
this.id = 123;
this.restApiKey = 'secret';
next();
};
app.models.Application.register(
user.username,
'demo-app',
{
publicKey: sslConfig.certificate
},
function(err, demo) {
if (err) {
console.error(err);
} else {
console.log('Client application registered: id=%s key=%s',
demo.id, demo.restApiKey);
}
}
);
});
}
I don't get any errors when the server starts up. Thoughts?
Got it figured. More information here https://github.com/strongloop/loopback-gateway/issues/17, but basically I had my rest-api middleware not configured right.

Categories

Resources