Two static directories (public+private) in node.js Express framework - node.js

The idea is the follow:
Send the login directory when the user is not authenticated.
Send the app directory one time that the user logs in (in this case, using passport module).
Example:
Not logged:
request: GET /
response: index.html from PATH_login
Logged:
request: GET /
response: index.html from PATH_app
I tried this but it didn't work:
app.use(function(req,res,next){
if ( req.isAuthenticated() )
{
// user is authenticated
return express.static(PATH_app)
}
else
{
// user is not authenticated
return express.static(PATH_login)
}
});

On initialization, you're setting that the middleware function that does the switching should be called for every request.
You should also initialize each of the middleware functions that would be switched between at this time.
At runtime for each request (when the code in the function you pass to app.use gets run), for that switching function to forward to the appropriate middleware, it would call the relevant function:
var appStatic = express.static(PATH_app);
var loginStatic = express.static(PATH_login);
app.use(function(req, res, next) {
if (req.isAuthenticated()) {
// user is authenticated
return appStatic(req, res, next);
} else {
// user is not authenticated
return loginStatic(req, res, next);
}
});

Related

Middleware Called before any request in ExpressJS

I am developing a NodeJS Api and having some issues with middlewares.
routes are accessible to user based on their roles and a role could be Admin or superAdmin.
My permission middleware looks like this:
permission.js
// middleware for doing role-based permissions
const { getRoleName } = require('../../constants/roles');
module.exports = function permit(...allowed) {
const isAllowed = role => allowed.indexOf(role) > -1;
console.log(isAllowed)
// return a middleware
return (req, res, next) => {
//findRole Name
if (req.user && isAllowed(getRoleName[req.user.role]))
next(); // role is allowed, so continue on the next middleware
else {
res.error({ code: 403, message: 'Forbidden', errors: ['Permission Denied'] }); // user is forbidden
}
}
}
I also have an authentication middleware which attaches logged in user to req.user.
I am using this permission-based middleware into my routes Like this.
records.js
const permit = require("../middlewares/permissions/permission");
router.get("/", permit("superAdmin"), getAllRecords);
router.get("/route1", permit("admin"), getRouteOneRecords);
router.get("/route2", permit("admin","superAdmin"), getRouteTwoRecords);
Now the problem is when my app runs all the roles are printing without making any request,
console.log(isAllowed), this line in permission.js is printing the roles without any request made to any of the routes.
I wonder why this is happening, even before making a request to the route.
just because in each route you are executing the permit() method, inside of that you are executing this block before return your middleware function:
const isAllowed = role => allowed.indexOf(role) > -1;
console.log(isAllowed)
// return a middleware
But for sure that the content for this function return (req, res, next) => { are gonna be executed as the middleware purpose when you execute the route.

How to apply instance of use() to all routes except those handed by app.use(express.static("dist"))?

I think I have resolved this issue in the process of writing it, basically the solution seems to be:
Move the static file handler above the other instance of use()
Confirmation that this is an acceptable approach would be appreciated though and perhaps help others in a similar scenario.
Desired Behaviour
Apply a use() instance to all routes except those handled by:
app.use(express.static("dist"));
Actual Behaviour
use() is being applied to all routes, including those handled by:
app.use(express.static("dist"));
Scenario
For securing access to API's, I am using the model described in this Lynda.com tutorial:
Node.js: Securing RESTful APIs
In pseudo code, the model is essentially comprised of:
a global use() instance that checks if a jwt token has been sent
if a token has been sent, if verifies the token
it sets the req.user property to undefined if verification fails or a token wasn't sent
otherwise, it sets the req.user property to the decoded jwt value if verification succeeds
subsequent middleware performs conditional behaviour based on the value of req.user
This model is working well for all intents and purposes.
However, I recently added some console logging and can see that verification is being performed for both:
api requests (desired behaviour)
static files served via app.use(express.static("dist")) per this convention (undesired behaviour)
Question
How can I apply the verification use() instance to all routes, except those handled by app.use(express.static("dist")).
What I've Tried
I think I have resolved this issue by moving section 2 of the code below above section 1.
// 01. verification use() called on all requests
app.use((req, res, next) => {
// if jwt authorisation has been sent in headers, verify it
if (req.headers && req.headers.authorization && req.headers.authorization.split(' ')[0] === 'JWT') {
console.log("jwt verification sent, verifying...");
try {
// this is synchronous as it has no callback
req.user = jsonwebtoken.verify(req.headers.authorization.split(' ')[1], 'RESTFULAPIs');
console.log("jwt verified, will return decoded value");
} catch (err) {
req.user = undefined;
console.log("jwt verification failed, user will remain undefined: " + err);
}
// move to the next piece of middleware
next();
}
// if jwt authorisation has not been sent in headers
else {
console.log("jwt verification not sent, leaving user as undefined");
console.log(req.originalUrl);
req.user = undefined;
// move to the next piece of middleware
next();
}
});
// 02. use() for serving static files
app.use(express.static("dist"));
// 03. middleware to check if login has been verified
const api_login_required = (req, res, next) => {
// if token verification was successful and the user property exists
if (req.user) {
// move to the next piece of middleware
next();
}
// otherwise, return unauthorised user message
else {
res.json({ verification: 0 });
}
}
// 04. middleware called in route handlers
app.route("/api/:api_version/users/private_data")
.get(api_login_required, api_users_private_data_get)
.post(api_login_required, api_users_private_data_post);
Middleware always controls the flow from to button in which order they wrote. Like
if (example 1)code like
app.use((req,res, next)=>{// middleware 1; next()} )
app.get('/rot1', (req, res)=> res.status(200).send('route 1'));
app.get('/rot2', (req, res)=> res.status(200).send('route 2'));
In this case, middleware appears in both route1, route because of middleware set at the top of the route.
If (example 2)code like
app.use((req,res, next)=>{// middleware 1; next()} )
app.get('/rot1', (req, res)=> res.status(200).send('route 1'));
app.use((req,res, next)=>{// middleware 2; next()} )
app.get('/rot2', (req, res)=> res.status(200).send('route 2'));
Here middleware1 applied in both route1 and route 2
But middleware2 applied only on route2.
But you can also define specific middleware for each route
function middleware1(req, res, next){
next();
}
function middleware2(req, res, next){
next();
}
app.get('/rot1', middleware1, (req, res)=> res.status(200).send('route 1'));
app.get('/rot2', middleware2, (req, res)=> res.status(200).send('route 2'));
Here middleware1 only applied on route1 and middleware2 only applied on route2.
Maybe above explanation help you!!

skip token verification for GET request

I want skip token verification for GET method in express. I want to allow GET request for everyone while just post, put, delete request by authorized user.below is my logic but the response hanging. I tried to used nested express use method.
app.use(function(req, res, next) {
if (req.method === 'GET') {
app.use('/api/someroute', routes);
}
else{
//do verification below the next
next();
}
})
or is there any other way to handle this
Just include a middleware on desired routes :
var router = express.Router();
// no middleware included for get request
router.get("/route1", handlerRoute1);
router.get("/route2", handlerRoute2);
// include some middleware
router.post("/route3", myMiddleware1, myMiddleware2, handlerRoute3);
app.use(router);
Where myMiddleware1 and myMiddleware2 looks like :
myMiddleware1 = function(req, res, next){
// verify token, etc, ....
var success = true;
// call next on success
if(success)
return next();
else
{
// raise error
return res.status(500).json({error: "Missing token..."});
}
};
It's because in the scenario for GET requests you don't actually complete the request (or move on from that middleware). Middleware is processed in sequential order i.e. first come first served. If you only want to protect everything other than GET requests then something like this would be fine:
app.use(function(req, res, next) {
// let GET requests through
if (req.method === 'GET') return next();
// perform token auth on all other requests, next() if OK
});
// setup routes
app.use('/api/someroute', routes);
You would setup your middleware first then declare your routes after, this means any requests coming in will have to pass through your token check, in this case you just skip GET requests.

Page displays 'null' after authentication

I'm creating a simple PWA to draw in multiple data sources into one application. I'm currently trying to set up authentication using a combination of passport and the twitter-strategy.
After the user has successfully authenticated they're account, twitter redirects to the callback endpoint, with the valid user data.... essentially the auth has been successful. However, when sending the user back to the client side application a html document with the word null is presented, rather than the application.
With the following code, I expect:
Twitter to return to callback URL
Server to perform actions in authSuccess function
Redirect to the provided url on the client
routes.js to server the application shell via the catch all route
Client application to boot and handle the URL served
Currently, only the first two steps are successful, and the app simply displays null (with the correct url in the address bar), rather than the expected output. Changing the location of the writeHead() call to / works, and the user is authenticated as expected ().
routes.js
let users = require('../controllers/userController');
app.get('/user/auth/twitter/callback',
passport.authenticate('twitter', {
failWithError: true
}),
function(req, res) {
console.log('[Twitter] Auth success route hit');
users.authSuccess(req, res);
},
function(err, req, res, next) {
console.log('[Twitter] Auth failure route hit');
users.authFailure(err, req, res, next);
}
);
app.get('*', function(req, res){
console.log('[Route] Catch All: ' + req.path);
res.sendFile(path.resolve(__dirname, '../../public/index.html'));
});
userController.js
authSuccess(req, res) {
console.log('[User Controller] User',req.user);
// Set some cookies here
res.writeHead(302, {'Location': '/user/profile'});
// res.redirect('/user/profile');
res.end();
}
Any help much appreciated. If you need more code, just ask :)
Thanks

Using Express 4 how to redirect to my own route without losing req and response data?

I have my application structured with 3 Routes (api, admin, default). Each lives in there own file and has it's own middleware and exports a Route. The problem I am facing is when I want to forward to another route that lives on a different router. Essentially I want to call the same function so that I am not serving up the same view from multiple locations.
I don't want to user res.redirect('/someplace') because I want to be able to pass the req and res objects on to the method.
|-app.js
|-routes
|---admin.js
|---api.js
|---default.js
The routes are required and used in app.js as follows
app.use('/api', require('./routes/api')(passport);
app.use('/admin', require('./routes/admin')(passport);
app.use('/', require('./routes/default')(passport);
Inside of admin if have a situation where I need redirect to login and pass some data
// authenticates all routes for the admin router
router.use(function(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.flashMessage.push('Session expired'); //is lost after redirect
res.redirect('/login');
//do I need to restructure my whole app so that I don't
//have to call res.redirect('login')
});
Any ideas on how to structure this? Do I need to export every method and keep all of my routes in one router file? That doesn't very clean, but if the functions are somewhere else it may be too messy.
You can forward it by calling the next callback ,but only if you do not use any paths.
app.use(function(req, res, next) {
// ... api
next();
});
app.use(function(req, res, next) {
// ... admin
next();
});
Another option is use * that will match all paths:
app.use("*", function(req, res, next) {
var path = req.path; // just example how it can be done
if (path === "/api") {
// ...
path = "/admin";
}
if (path === "/admin") {
// ...
}
});
Edit:
I don't think that express has something like next('/login'); ,so basically function that can forward a request to another path and I don't think that is right to have something like this. If a client ask for /admin you should send this particular page and not the page that is under /login. If you want to send back to a client the login page than just redirect it as you did it in your question. I understand that you want to keep the req, res ,but then is the problem in the proposal/structure of your webapp.

Resources