I am storing a parking detail with a merchant id in the mongoose schema since a parking belongs to a certain merchant user and it cannot be empty or null.
Here is the model:
const parkingSchema = new mongoose.Schema({
merchantId: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Merchant",
},
//other details
})
merchant model is something like this:
const merchantSchema = new mongoose.Schema({
merchantId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Auth",
},
//other details
})
And finally the auth schema:
const authSchema = new mongoose.Schema({
accountType: {
type: String,
required: true,
trim: true,
default: "user",
enum: ["merchant", "user", "provider"],
},
//other details
})
If the original user wishes it, I simply want to update the parking data; otherwise, I want to throw an error.
I am using jsonwebtoken to authenticate users.
Here is the query to update the data:
exports.updateParking = async (req, res) => {
try {
const { parkingName, price, address, name, phoneNumber, about } = req.body;
const { parkingImage } = req.files;
const check_exist = await Auth.findById(req.data.id);
if (!check_exist) return res.status(404).json({ error: "User not found" });
console.log(req.data.id);
const updateData = await Parking.findByIdAndUpdate(
{ _id: req.params.id, merchantId: req.data.id }, // I think here is the problem
{
$set: {
parkingName,
price,
address,
...
},
}
);
return res.status(200).json({
success: true,
msg: "Parking has updated successfully",
});
} catch (error) {
return error.message;
}
};
However, the issue is that other users can now update another user’s data which I want to stop
below is the query of middleware:
routing.patch("/parking/update/:id", middleware.authenticateToken, merchant.updateParking)
2
Answers
You should be showing each user only their parkings that they have created or belong to them.
you have to set this
req.user._id
when user logins. You could create a session.I think what you’re looking for is something like CASL Mongoose (or a similar package), and more specifically, the "conditions" section of the CASL docs.
What you’re dealing with here is the distinction between 2 concepts:
In your app,
middleware.authenticateToken
is responsible for the AuthN piece of the equation. It makes sure that only users that have created an account are able to make requests to your API routes.What you still need to solve for is the AuthZ piece, which can be done in a bunch of different ways, but one popular one is to use CASL, which is a Node AuthZ library that allows you to utilize your ORM’s native query syntax to limit actions based on the authenticated (AuthN) user’s attributes.
In other words, you can do something like, "Only allow user with ID 1 to update
Parking
entities that he/she owns". Below is generally what you’re looking for (not tested for your use case, but the general idea is here):Additional comments/notes:
try/catch
handler and using an Express default error handler as it will reduce the boilerplate you have to write for each route.req.user
so you always havereq.user
available to you in your authenticated routes.