So I'm serving a web page on the root route '/', and this page had an authentication middleware. Using regular
app.use('/', authorizeFront, express.static('../client/dist'));
would cause every route to be authenticated, which is what I'm trying to avoid. I've also tried using regex to match exactly '/' but it doesn't seem to be working.
app.use('/^/$/', authorizeFront, express.static('../client/dist'));
Is there any official way to do this? Thanks!
Another way to do this could be:
app.use("*", (req, res, next) => {
if (req.baseUrl === "") { // For / requests baseUrl will be empty
// Call authenticator and then call next() if auth succeeds else call next(err)
} else {
console.info("Bypassing Authentication");
next();
}
});
This will hit the middleware for all requests, but you have the control for which request you want to call the authenticator.
app.use does a partial match. Use app.get instead.
When using app.use("/") this will match any path and method that starts with "/",
This happens because app.use() is intended for global middlewares.
Instead you can use app.get("/", yourTargetedMiddlewaer) to target a specific route and a specific method (GET) in this case.
app.use(express.static(path.join(__dirname, 'public')));
app.use(function(req, res, next) {
if ( req.path === "/") {
console.log("request matches your special route pattern", req.url);
// return authorizeFront(); call your code
}
next();
});
app.use('/', indexRouter);
app.use('/users', usersRouter);
I tested this and my console prints only when i use URL like this:
http://localhost:3000/ or http://localhost:3000
Also notice the sequence of middleware I have used, base root middleware should be set at top.
You can do more modification as per your needs
Related
I am trying to add a validation middleware in order to protect my server data. When I get request (http://localhost:3000/filepath) the static route without the middleware:
app.use(express.static('data'));
I get a status 200 OK. But when I tried to get request the same route, but this time using a simple middleware as recommended in this other question (Is it possible to use validation with express static routes?)
var staticMiddleware = function(req, res, next){
console.log("middleware")
next();
}
app.use(staticMiddleware, express.static('data'));
I`ve got a status 404 not found.
How can I add another middleware to app.use before the express.static middleware?
You need to add them seperately.
app.use(express.static('data'));
var staticMiddleware = function(req, res, next){
console.log("middleware")
next();
}
app.use(staticMiddleware );
Why I enter http://localhost:3000/product on the browser, the output will be both outputs of '/' and '/product'?
Please look at this snippet code.
const express = require('express');
const app = express();
// http://localhost:3000/product
app.use('/product', (req, res, next)=>{
console.log('In product page');
res.send('<h1>Product Page</h1>');
});
// http://localhost:3000/
app.use('/', (req, res, next)=>{
console.log('In main page');
res.send('<h1>Main Page</h1>');
});
app.listen(3000);
This image is my app's output.
It could have multiple reasons. One that I think of right now is that the browser requests http://localhost:3000/favicon.ico automatically after product.html, which triggers the use('/', ...) route.
Maybe you should use app.all(...) instead of app.use(...), to avoid this "wildcard" on every path that should rather be a 404 page.
The app.use() method is used to bind application level middleware. Not for accepting GET request as you are expecting.
You should use
// http://localhost:3000/product
app.get('/product', (req, res)=>{
console.log('In product page');
res.send('<h1>Product Page</h1>');
});
// http://localhost:3000/
app.get('/', (req, res)=>{
console.log('In main page');
res.send('<h1>Main Page</h1>');
});
Because in express whatever you define with app.use() is middleware and it always executes until and unless it has some path defined
app.use('/', (req, res, next)=>{
console.log('In main page');
res.send('<h1>Main Page</h1>');
});
above will always execute because it contains root path and every url has root path
Check this link for further info https://expressjs.com/en/4x/api.html#app.use
You should define your routing with express router using app.get("/") or app.post("/") and it will help for more info https://expressjs.com/en/guide/routing.html
I am trying to setup a multi language website with Express and NodeJs. My problem is I get redirected what it feels like 100 times and my browser is giving me a error that the webpage is not working because it redirected me too many times.
app.js
app.use('/', (req,res,next) => {
res.redirect('/en-US');
next();
});
app.use('/:lang', indexRouter);
app.use('/:lang/users', usersRouter);
index.js (indexRouter)
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
module.exports = router;
The problem is that this route handler:
app.use('/', (req,res,next) => {
res.redirect('/en-US');
next();
});
will get hit for not only /, but also /en-US. app.use() matches any route handler for which the path is equal to or a subset of the requested path. So, the browser requests "/", you redirect to "/en-US", which then redirects to "/en-US" and so on, an infinite loop.
I don't know the overall URL design of your site to know what the best overall solution is. You can prevent the infinite redirect loop by just changing app.use() to app.get():
app.get('/', (req,res,next) => {
res.redirect('/en-US');
});
But, that will make the redirect only work for GET requests which may or may not be OK. If you want all HTTP verbs to redirect, you could change to app.all():
app.all('/', (req,res,next) => {
res.redirect('/en-US');
});
The important thing to understand here is that app.get(), app.post(), app.all(), etc... all require an exact match for the URL path, whereas app.use() just requires a subset match. This is a little understood aspect of the Express design.
In addition, remove the call to next() after you do res.redirect(). At that point, you've sent the response, you don't want any other request handlers to see the request. You're done with routing.
under your app.js
Try using
app.use('/', router )
How about you try dealing with the '/' route through the app.js directly instead of index.js
I'm creating an app using node, express, and have a passport authorization middleware implemented for all routes-. I am following a highly modular approach to build my app. I try to exclude specific APIs from authentication when I include them above the authorization middleware. But when I include app.use('/', require('./api/search/index')); above the authorization middleware, APIs beneath stop working.
Criticism and suggestion are all welcome for this approach and what can I do to resolve this problem.
I don't want to include route middleware in each route like this
route.get('/example', auth.middleware(), function (req, res) {
})
Below is my app approach with single authorization middleware for all routes
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var auth = require("./auth.js")();
app.use(auth.initialize());
//Excluding the search API from Authentication,
app.use('/', require('./api/search/index'));
//Middleware for all APIs and require Auth headers for authrization access
app.use(auth.authenticate(), function (req, res, next) {
if (req.headers.authorization && req.user) {
var parted = req.headers.authorization.split(' ');
if (parted.length === 2) {
console.log(req.user);
next();
} else {
return res.status(403).send({
success: false,
msg: 'Unauthorized.'
});
}
} else {
return res.status(503).send({
success: false,
msg: 'Bad Request'
});
}
});
//Join routers
app.use('/', require('./api/users/index'));
app.use('/', require('./api/product/index'))
app.use('/', require('./api/company/index'))
There are a million ways you can do this. What you can do is this:
app.use('/', require('./api/search/index'));
app.use('/', auth.authenticate(), require('./api/users/index'));
app.use('/', auth.authenticate(), require('./api/product/index'))
app.use('/', auth.authenticate(), require('./api/company/index'))
This way, the auth.authenticate() middleware will be applied to every child route you are requiring. And you leave the index without anything. This gives you a more granular control of where you apply the auth middleware, without having to apply it to every single route. You can take this to another level and group several routes inside a /admin/ and apply the middleware only once. Your imagination is the limit.
You can block your routes together using express.Router. For instance, you could have a route called "/api/secure" and then create a router for that route and group all secure routes there. and then have another for unsecured routes'
Express Router Docs
I'm fairly new to node.js and trying to make a simple website which first asks the authentication and then redirects the user to a page.
so, what i do is that i create a middleware which listenes to every request made to my website.
what this middleware does that it checks if the the user is logged in with my website or not is yes then redirect to the requested page if not, then redirect to the login page, here is my code for that.
var express = require('express');
var app = express();
// middleware for using static files
app.use('/public', express.static(__dirname + '/public')); // all the js files for check_before.html
app.use('/templates', express.static(__dirname + '/templates')); // here are css/js files for login.html
// setting up views folder
app.set('views', __dirname + '/views'); // check_before.html is sitting here
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use((req, res, next) => {
res.render('check_before.html');
// here in the html I implement the logic using js files which are located in public folder.
next();
});
// if not logged in , the user gets here
app.get('/login', (req, res, next) => {
res.render('login.html')
});
// if logged in redirect to some page
app.get('/welcome_page', (req, res) => {
return 'welcome'
});
everything goes well untill the user hits the http://localhost:8000/login page (after the check if they are signed in or not) the page keeps on loading multiple times and it won't stop reloading.
I have defined all the css, js files of login.html page in the templates folder which is loaded above the middleware by reffereing to this question
Express middleware getting called many times. could that be a problem?
what could be the reason for this?
here is the error i'm getting in the console.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
any guesses?
Edit1
I went through this question Error: Can't set headers after they are sent to the client , and i guess it concludes that setting headers explicitly could be problematic.
Could this be a reason? because in my logic if the user is not signed In, I'm just using window.location.replace('http://localhost:8000/login') to redirect the user to login page.
should I use any another method for redirection?
Edit2
There are suggestions that i must write a middleware to check is the user is authenticated or not, and get a sort of flag for that, but as i've stated above that i'm implementing the logic in check_before.html(client side). so it won't be possible to use that.
I have two guesses:
You shouldn't call send (or any other function )after res.render.
Middleware to verify user is logged in should be something like this (applied only to routes you want to verify user)
Middleware should be something like this
const isAuthenticated = (req, res, next) => {
if(req.isAuthenticated()) {
next();
} else {
res.redirect('/');
}
}
app.get('/welcome_page', isAuthenticated, (req, res) => {
return 'welcome'
});
The reason is that middleware is called before your /login request. To fix it, you need to modify your middleware function. It should be something like:
app.use((req, res, next) => {
if(isLoggedIn) { //isLoggedIn is a flag that checks whetehr user is logged-in or not
res.render('check_before.html');
} else {
// here in the html I implement the logic using js files which are located in public folder.
next();
}
});