I have a bug which has made me realize I clearly missing something important about express middlewares. I have something like this:
const checkAuth = ({ allowedRoles = [], targetUserId }) => {
return async (req, res, next) => {
console.log(targetUserId);
//Do checks
if(!allowedRoles.includes(req.user.role) return
targetUserId = req.params[targetUserId]
if(!allowedUsers.includes(targetUserId) return
return next();
};
};
app.get(
"/activity/:id",
checkAuth({ allowedRoles: ["locationAdmin", "orgAdmin"], targetUserId: "id" }),
async function (req, res, next) {
//Do things
});
});
The idea behind this middleware is the 'targetUserId'variable tells it which request parameter to look in for a value, then it can choose to authorize the request with the value it finds there. The middleware actually exists in it's own file/module if that makes any difference.
Here's what I expect to happen:
- User loads url /activity/23 > "id" is logged
- User loads url /activity/23 > "id" is logged and so on until the end of time...
What actually happens:
- User loads url /activity/23 > "id" is logged
- User loads url /activity/23 > 23 is logged
- User loads url /activity/23 > undefined is logged
- User loads url /activity/23 > null is logged item 4 will then repeat forever
My expectation is that each time checkAuth is called, there should be nothing in memory from it's last call. It's taken me a couple of hours to get my head around this, but what seems to be happening, is after the value of targetUserId is set within the middleware, the variable remains set in memory, and isn't changed when it gets called again with "id". This explains why the value logged to the console changes 3 times on repeat requests for the same page.
But why does it do this and how can I fix it?
CodePudding user response:
The way your code is structured, checkAuth()
is called once when your code is first run. That captures the arguments you passed it and then makes those available to the middleware function that checkAuth()
returns and that middleware function is passed to Express where it is registered as middleware for this request handler.
That middleware function you return is then called by Express for each incoming request that matches this request handler. The arguments you passed to checkAuth()
are available to that middleware function each time it is called.
If some code changes those arguments (like code inside the middleware itself changes an object or property passed), then those changes are persistent (in a closure) and future middleware will see those changes. So, if you need to modify those arguments for the purposes of one request, then you should make a copy of the data or make the modifications in a variable that is local to the internal middleware function.