I'm setting up dynamic routes and using basicAuth (when a user/pass has been configured). Here's what I have:
var basicAuth = express.basicAuth,
auth = function(req, res, next) {
if (config.hasOwnProperty(req.params.project)) {
var auth = config[req.params.project].auth;
if (auth) {
basicAuth(function(user, pass, callback) {
// Check credentials
callback(null, user === auth.user && pass === auth.pass);
})(req, res, next);
} else {
// No authentication
return true;
}
}
};
Then, my route looks like this:
app.get("/:project", auth, function (req, res) {
...
});
It's getting the config from a file which either contains the auth object with auth.user and auth.pass or is set to false. When set to false I'd like to (obviously) skip authentication.
The basicAuth is working when turned on, but I can't figure out how to dynamically bypass it.
Connect doesn't check the return value of the middleware, so returning true doesn't mean anything. You need to call the next function so that Connect knows to continue.
var basicAuth = express.basicAuth,
auth = function(req, res, next) {
if (config.hasOwnProperty(req.params.project)) {
var auth = config[req.params.project].auth;
if (auth) {
basicAuth(function(user, pass, callback) {
// Check credentials
callback(null, user === auth.user && pass === auth.pass);
})(req, res, next);
} else {
// No authentication
next();
}
}
};
Also, it looks like the basicAuth callback can be synchronous, so it's probably cleaner to do this:
basicAuth(function(user, pass) {
// Check credentials
return user === auth.user && pass === auth.pass;
})(req, res, next);
Finally, basicAuth has another alternate form, so you can just do:
basicAuth(auth.user, auth.pass)(req, res, next);
Related
How do Allow only Admins to have access to the Admin page in AdminBro? Nodejs
All that I want is for only Admins to have access to the adminBro page, is there any specific method to get this done?
I did this in my app.js file but it's not working
app.get("/admin", function (req, res, next) {
res.locals.login = req.user;
if (res.locals.login.roles == "admin") {
app.use("/admin", adminRouter);
} else {
res.redirect("/");
}
});
You cannot use new app.use inside app.get, as (req, res, next) are already consumed. You have two of choice:
Your route in if condition body
if (res.locals.login.roles === 'admin') {
// your admin route logic
res.send('admin page')
} else {
res.redirect('/')
}
I'm used to use small middleware function like this one:
const isAdmin = (req, res, next) => {
if (req.user.roles === 'admin') {
return next();
}
res.redirect('/');
};
Then you use it in whichever route this way:
app.get('/admin', isAdmin, adminRouter)
I'm using Express and Express-JWT.
In a Express() instance I use:
const api = express()
api.use(jwt({
// my options
}))
To mock this in tests, I use a mocks\express-jwt\index.js file containing:
const jwt = jest.fn().mockImplementation(options => (req, res, next) => {
// set dummy req.user and call
next()
})
module exports = jwt
This all works fine.
Now I want to skip JWT for the root endpoint, so I changed the jwt usage to:
api.use(jwt({
// my options
}).unless({path:['/']}))
In my mock file I added:
jwt.unless = jest.fn().mockImplementation(options => (req, res, next) => {
next()
})
However, the tests now always fail with function unless is not defined.
Anyone an idea how to mock this unless behaviour?
unless is being used as a property on the result of calling jwt.
So to mock it, add your unless mock as a property of the function returned by your jwt mock:
const jwt = jest.fn().mockImplementation(options => {
const func = (req, res, next) => {
// set dummy req.user and call
next();
};
func.unless = jest.fn().mockImplementation(options => (req, res, next) => {
next();
});
return func;
});
module.exports = jwt;
Suggested answer by Brian did not work for me, because in the func method I do some stuff for faking an authorization check.
My problem was I needed to do skip the authorization check for the method+path given in by the unless function.
My solution now is like this:
const jet = jest.fn(options => {
let mockFunc = (req, res, next) => {
// get authorization from request
let token = ...
if (!token) {
res.status(401).send('No token provided')
} else {
req.token = token
next()
}
}
mockFunc.unless = jest.fn(args => (req, res, next) => {
if (args.method == req.method && arg.path == req.path) {
// not do authorization check for excluded endpoint via unless
next()
else {
mockFunc(req, res, next)
}
}
return mockFunc
}
Thanks to Brian for pointing me in the right direction.
I am trying to set it to true and only then redirect to another page. However I get redirected first and then it's set to true..
Code:
exports.logIn= function(req, res, next) {
req.session.loggedIn = true;
res.redirect("/home");
};
You can achieve this using res.locals
exports.logIn= function(req, res, next) {
//AUTHENTICATE
res.locals.loggedIn = true;
res.redirect("/home");
};
Then on '/home' route you can check the user is logged in or not by reading res.locals.loggedIn
if(res.locals.loggedIn){
// DO SOMETHING
} else {
//REDIRECT TO LOGIN
}
I would like to pass a certain permission into the authenticated call on routes in Passport.js.
This is what I have now:
app.get('/mypage', app.authenticated, function (req, res, next) {
if (!req.user.hasPermission('myPermission')) {
return res.redirect('/unauthorized');
}
// do stuff
};
var middleware = function(app) {
app.authenticated = function (req, res, next) {
if (req.isAuthenticated()) {
return next();
}
if (req.method == 'GET') {
req.session.returnTo = req.originalUrl;
}
res.redirect('/login');
};
}
module.exports = middleware;
I would instead like to pass the permission into authenticated like this:
app.get('/mypage', app.authenticated('myPermission'), function (req, res, next) {
// do stuff
};
But as far as I can tell, since authenticated gets the parameters it needs automatically, I can't just add a new one.
How can I go about doing this?
You can access req.body values in any of the express middleware.
In your app.authenticated(..) middleware, prior to execution set the value :
req.body['permission'] = 'myPermission'
Use the value of req.body['permission'] for authorisation.
I have a express route like this:
app.get('/', auth.authOrDie, function(req, res) {
res.send();
});
where authOrDie function is defined like that (in my auth.js module):
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.send(403);
}
});
Now, when the user is not authenticated, I would like to verify if the http request has a Authorization (Basic) header. To do that, I would like to use the great connect middleware basicAuth().
As you know, Express is built on top of Connect, so I can use express.basicAuth.
The basicAuth is generally used like that:
app.get('/', express.basicAuth(function(username, password) {
// username && password verification...
}), function(req, res) {
res.send();
});
But, I would like to use it in my authOrDie function like that:
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else if {
// express.basicAuth ??? ******
} else {
res.send(403);
}
});
****** How can I call the basicAuth function with the good parameters (req ? res ? next ? ...).
Thanks.
Calling the express.basicAuth function returns the middleware function to call, so you'd invoke it directly like this:
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
return express.basicAuth(function(username, password) {
// username && password verification...
})(req, res, next);
}
});