I created two uploads folder are public and private. Public folder does not require auth but private folder will require a middleware to access;
app.use('/uploads', express.static('uploads/public/'));
app.use('/uploads', require('./admin/routers/api/accessPrivate'), express.static('uploads/private/'));
And here is my accessPrivate
const userPermission = require("../../middleware/permission");
const auth = require('../../middleware/auth');
const accessMedia = async ( req, res, next) => {
await auth(req, res, next);
next();
};
module.exports = accessMedia;
But it shows error: "No token". It means that there is no req header sent to server; Can you tell me how to do?
Thank you so much;
Define a general middleware for all uploads requests. Check the user's permission.
app.use('/uploads', async (req, res, next) => {
let hasAccess = await auth(req, res, next);
if (hasAccess) {
app.use(express.static('uploads/private/'));
}
else {
app.use(express.static('uploads/public/'));
}
next();
});
// your routes
app.use('*', function (req, res, next) {
let target = 'index.html';
if (req.baseUrl && req.baseUrl != '/') {
target = req.baseUrl;
}
if(req.user) {
root = 'uploads/private/';
}
else {
root = 'uploads/public/';
}
res.sendFile(target, { root: root })
});
Also you should change the auth implementation.
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 have a script which holds a middleware like:
module.exports = function (req, res, next) {
req.requestTime = Date.now()
next()
}
In a file I can import this but how can I write multiple middleware and export all of them and import it?
I am learning express and got stuck here :)
write multiple middlewares in one file and exprot them all.
function middleware1(req, res, next) { req.requestTime = Date.now(); next() }
function middleware2(req, res, next) { req.requestTime = Date.now(); next() }
function middleware3(req, res, next) { req.requestTime = Date.now(); next() }
module.exports = {
middleware1 : middleware1,
middleware2 : middleware2,
middleware3 : middleware3
}
then if you want to import them you can either import all of middlewares like
var middleware = require("./middlewares")
// name of middleware file in require
then use them like
app.get('/profile', middleware.middleware1, function (req, res) {
// do your stuff
});
Or you can import a single middleware by adding middleware function name in require
var middleware1 = require("./middlewares").middleware1
then use them like
app.get('/profile', middleware1, function (req, res) {
// do your stuff
});
I was trying to do the same, but my scenario was a bit different
I had type module in package.json
{
"type": "module"
}
middleware file and exporting
const authenticate_middleware = (req, res, next) => {
const authHeader = req.headers.authorization;
if (authHeader) {
const items = authHeader.split(' ');
/*check count 2*/
/*check 1st item is barner*/
/*check and validate 2nd item*/
const token = items[1];
let user = {
id: 1,
token: token
}
req.user = user;
next();
} else {
res.sendStatus(401);
}
};
const developer_middleware = (req, res, next) => {
const authHeader = req.headers.developer; /*all lower case apiKey was undefined*/
if (authHeader) {
let developer = {
id: 1,
apiKey: authHeader
}
req.developer = developer;
next();
} else {
res.sendStatus(401);
}
};
export default authenticate_middleware;
export let authenticate = authenticate_middleware;
export let developer = developer_middleware;
importing modulewares
//import multiple
import { authenticate, developer } from '../middlewares/all.js'
//import single
import { developer } from '../middlewares/all.js'
// import default
import authenticate from '../middlewares/all.js'
I am trying to add two authentication controllers to one route. For example, this is basically what I am trying to make:
router.route('/employees')
.get(authController1.isAuthenticated, myController1.get1)
.get(authController2.isAuthenticated, myController2.get2);
The isAuthenticated function is as follows:
exports.isAuthenticated = passport.authenticate('basic', {
session: false
});
Does anyone know how this would be possible?
Thanks,
Daniel
Route:
router.route('/employees')
.get(authController.isAuthenticated1, authController.isAuthenticated2, myController1.get1)
authController :
exports.isAuthenticated = function(req, res, next) {
// Authentication code
if (!req.isAuthenticated) {
// Not authenticated
return res.status(401).send({
message: 'User is not authenticated'
});
}
next();
};
exports.isAuthenticated2 = function(req, res, next) {
// Authentication2 code
if (!req.isAuthenticated2) {
// Not authenticated
return res.status(401).send({
message: 'User is not authenticated'
});
}
next();
};
myController
exports.get1 = function(req, res) {
// Both are authenticated so we can proceed.
}
Perhaps something like this?
exports.isAuthenticated = function(req, res, next) {
req.user == 'type1' ? fnType1(req, res, next) : fnType2(req, res, next); // Do check and call method.
};
function fnType1(req, res, next) {
//Authentication code
// Attach type to req
req.userType = 1;
next();
}
function fnType2(req, res, next) {
//Authentication code
// Attach type to req
req.userType = 2;
next();
}
exports.get1 = function(req, res) {
// Both are authenticated so we can proceed.
if(req.userType = 1){
// Do something
} else {
// Do something else
}
}
this is my app.js
function requireLogin(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.redirect("/");
}
}
/**
* Routes
*/
var index = require('./routes/index');
var dashboard = require('./routes/dashboard');
app.use('/', index);
app.use('/dashboard', requireLogin, dashboard);
routes/dashboard.js
var express = require('express');
var router = express.Router();
router.route('/')
.get(function (req, res, next) {
res.render('dashboard/index', {});
});
module.exports = router;
After doing the login I am directed to the route /dashboard, but I get a status 404.
If I try to remove the function requireLogin, the route /dashboard is visible and working.
Why?
I did some tests, and I saw that the problem is next().
For the login I used passport is working well.
If you still haven't figured out you can put return next() instead of next().
So this:
function requireLogin(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.redirect("/");
}
}
Should become this:
function requireLogin(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.redirect("/");
}
}
Hope I helped!
Actually I had a very similar issue, for me it wasn't anything to do with the middleware that was handling authentication, it was the way my routes were set up.
I think you are trying to receive GET requests on a route you want to POST credentials to in dashboard.js:
router.route('/')
.get(function (req, res, next) {
res.render('dashboard/index', {});
});
should be:
router.route('/')
.post(function (req, res, next) {
res.render('dashboard/index', {});
});
since you are posting credentials to that route.