I have an app running in node, express, and angular. It has 2 pages, a user profile page and a login page. I want to make it so that if the user is not signed on and when the profile page is reached, I will redirect you to the login page. The problem is, somehow every time I try to redirect the user in node my Angular app doesn't receive the 302 redirect call (the response is always 200 even when I'm not sending any 200 status message responses). Any help is appreciated. Here is my code:
Node js:
// serve index and view partials
app.get('/', routes.index);
app.get('/partials/:name', routes.partials);
//authentication
app.post('/login', auth.login);
app.get('/logout', auth.logout);
app.get('/user', auth.getCurrentUser);
...
function getCurrentUser (req, res) {
var user = req.user;
if (user && user.username) {
console.log("getCurrentUser succeeded on user "+ user);
res.json({
username: user.username
});
} else {
console.log("getCurrentUser failed")
res.redirect('/login');
}
}
...
//routes in node
exports.index = function(req, res){
console.log("rendering index page");
res.render('index');
};
exports.partials = function (req, res) {
var name = req.params.name;
res.render('partials/' + name);
};
angular:
when('/login', {
templateUrl: 'partials/login',
contorller: LoginCtrl
}).
...
when('/user', {
templateUrl: 'partials/user',
controller: UserCtrl
})
function UserCtrl($scope, $http, $location, $routeParams) {
$http.get('/user').
success(function(data, status, headers){
console.log("/user succeeded with status "+status);
//redirect the user
if (status == 302){
console.log("302 received, redirecting user to "+headers().location);
$location.path(headers.location);
}
console.log("CLIENT : "+data.username);
$scope.username = data.username;
});
};
Output on server when /user page is reached:
getCurrentUser failed
GET /user 302 8ms - 40b
rendering index page
GET /login 304 80ms
rendering index page
Output on client:
/user succeeded with status 200
The 302 sent back by Express is handled by your browser, before Angular even gets its hands on it (so you can't create an interceptor for it).
A solution would be to always return a JSON object, and set some property on it that you can check for in Angular.
Related
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();
})
};
I am running into an issue with Passport.js in which I want to get the currently logged in users information from a Post request and process some stuff. When I console.log(req.user) it comes up as 'undefined'. The set up and authentication all works, I can also retreive user's info using a Get request as seen from the first code snippet.
router.get('/', function(req , res){
console.log("The current logged in user is: " + req.user.first_name);
res.render('index.ejs' , {
user: req.user
});
});
^ returns user's name as expected
router.post('/testPost' ,function(req , res){
console.log("The current logged in user is: " + req.user);
res.json({
status: "success"
});
});
^returns undefined even when the user is logged in.
I have seen the same question raised here How to get req.user in POST request using passport js two years ago but there was no answer.
It's because the user might not be logged in at the time you're checking it.
To ensure that a user is logged in when accessing a route you should have a middleware that checks it for you.
You can write it as a separate module and import it in every single one of your routes if it's required.
The module:
module.exports = {
EnsureAuthenticated: (req, res, next) => {
if (req.isAuthenticated()) {
return next();
} else {
res.sendStatus(401);
}
}
};
The routes:
//Destructuring | EnsureAuth Function
const {
EnsureAuthenticated
} = require('../path/to/the/module');
//You should get your user here
router.get('/', EnsureAuthenticated, (req, res) => {
console.log(req.user)
});
I am trying to add SAML authentication using passport-saml for my application. I am using Angular for routing. On loading of the homepage, I check for a user through a GET request to my node server "/auth" to check req.user, if it's true, I send back logged in user data; if false, I send back an error message. I have data binding on this user data response so in the event of no user data, I still show "Log in" button.
On click of the "Log in" button, I perform a redirect to the node server "/login". This does passport.authenticate function which runs and then ties in with "/assert" when it's complete to perform a redirect.** It is at this point I am running into a problem.** My redirect always goes to "/" because I am performing a redirect and using angular routing so I dont know how to store this route say "/myPage1" or "/myPage2". NOTE: I do not want to always send back to "/myPage1", I want to be able to "Login" from any view in the SPA.
Am I going about this in the wrong way? Is this a limitation of using Angular routing?
Angular
$scope.login = function () {
window.location.href = 'http://example.com/login';
};
function getCreds() {
$http.get('http://example.com/auth', { withCredentials: true })
.then(function (response) {
$scope.creds = response.data;
});
}
Node.js
app.get('/login', passport.authenticate('saml', { failureRedirect: '/login' }));
app.post("/assert", passport.authenticate('saml', { failureRedirect: '/login' }), function (req, res) {
// console.log('session' + JSON.stringify(req.session));
// console.log("original url " + req.session.originalUrl);
if (req.session.originalUrl) {
res.redirect(req.session.originalUrl);
}
else {
res.redirect('/');
}
});
app.get('/auth', function (req, res) {
var authenticated = req.user;
if (authenticated) {
res.send(req.user);
} else {
res.send({statusCode: 401, message: 'User session is not alive'});
}
});
I have found a way to achieve the desired effect.
Before making the "Login" call, I make another api call to "/setSessionRedirectUrl" which passes the current window.location.href from angular to node server for session storage.
app.post('/setSessionRedirectUrl', function (req, res) {
req.session.samlLoginRedirectUrl = req.body.redirectUrl;
res.send();
});
Then when the assert function is being run after login, it is looking for the req.session.samlLoginRedirectUrl to redirect to. It works!
I have some troubles with geting single user basing on his ID. I can remove this certain user with DELETE in my app but I can't get informations about him using "GET".
this is my angular app.js
app.controller('editUser', function($scope, $http, $state) {
$http.get('users/editUser/'+$state.params.userId).success(function(data) {
console.log(data);
});
});
and this is my users.js routes file
router.get('/editUser/:userId', ensureAuthenticated, function(res, req, next) {
var userId= req.params.userId,
data;
getUser.findOne({'_id': userId}, function(err, user) {
if(err) throw err;
data = user;
res.json(data);
});
});
after clicking on "edit" button I am redirected to users/editUser/ffw23rfaw - its id, and basing on this id I use get function to get info about him but I get 500 "Internal server error". I would like to add that removing user is pretty much same and it works.
after clicking Edit button I do this
$scope.editUser = function($index) {
$state.go('editUser', {userId: $index});
}
that's how I get userId on 'users/editUser/' page
and this is my state config
.state('editUser', {
url: '/users/editUser/:userId',
templateUrl: '/views/editUser.html'
})
Found out the issue :)
Your code has function(res, req, next)
Change that to
function(req, res, next)
just wrong placement of parameters (variable names).
Hope this helps. (thanks for pointing out the console message)
Suppose I have a script like this, which uses a Passport authentication strategy with an Express backend. How would I use this script to actually make API function calls? I don't see any explicit examples in the linked project's documentation nor can I find anything in Passport.js's documentation. Thanks.
After passport user serialization done, every request has user field, which contains information passed to done callback of passport.serializeUser method.
app.get('/userID', function (req, res) {
if (req.isAuthenticated()) {
res.json(req.user.id);
}
res.redirect('/login');
}
Also, you have access to session
app.get('/auth/fitbit/callback',
passport.authenticate('fitbit', { failureRedirect: '/login' }),
function(req, res) {
req.session.loggedInAt = Date.now();
res.redirect('/');
});
Information stored in session available in all requests, while user is authenticated
app.get('/someroute', function (req, res) {
// call to another service
var url = 'http://superservice.com/' + req.user.id + '/' + req.session.loggedInAt
http.get(url, function (_res) {
res.send(_res.data)
});
});
I'm supposing that you know how to use passport, and you will figure it out what's the right Fitbit API endpoint (honestly, I'm don't know it). Said that, let me give an idea that might help you solve your problem:
// An awesome npm module (https://github.com/mikeal/request)
var request = require('request');
//
//
//
// An express route.
app.get('/activities', function (req, res) {
if (req.user !== null) {
// User is authenticated.
getUserActivities(req.user.id, res);
} else {
// Redirect to login the user isn't authenticated.
res.redirect('/login');
}
});
// This function will make API calls to Fitbit
// using the User ID we got from the PassportJS
// authentication process.
function getUserActivities(id, res) {
// It will request from Fitbit User activities.
request('https://api.fitbit.com/1/user/'+ id +'/activities/',
function (error, response, body) {
if (!error && response.statusCode == 200) {
// If everything goes well.
return res.send(body);
} else {
// If something wrong happens.
return res.send(error);
}
);
}
The goal of this example is to show you that you need to use PassportJS to get fitbit users ID, then use that id to make API calls to fitbit.