Warm tip: This article is reproduced from serverfault.com, please click

How to identify a user with a token?

发布于 2020-11-25 20:41:46

I've got a mongoDB Atlas database named "test" and I do only deal with the backend.

There are 2 collections: sauces and users. (yes, it's about sauces)

my database "test" with 2 collections

I need to be sure that only the user who did create a sauce in the database can delete this sauce.

From the frontend, in the delete request, I do receive 2 things: a token (made with jwt), and the id of the sauce to delete.

The request of deletion

With the id of the sauce I can find the user who did create the sauce, meaning that I can also find the user in the users collection. An object user has got 2 properties: email and password (hashed with bcrypt).

in the sauce object, we can find the id of the user who did create the sauce: userId

here is a user object in the users collection

So I got the token from the frontend (req.body.token) and the id of the product (req.params.id).

With this: I do find the id of the user who did create the object.

So, I need to make a link between the token, and the userId.

I've tried to check the value of userId with jwt.sign, and to compare it with the token received. Problem: this token does change at each connection, so it's not the right way to do...

so my question is: from the backend (I can't touch the frontend) how I'm supposed to identify the user when I do only have the id of the object to delete and a token?

Questioner
RafaRemote
Viewed
0
Claudio Bonfati 2020-11-26 05:16:27

I would recommend you working with your Auth middleware function. In this function, you retrieve the user data from mongoDB (searching by token) and pass the user to your request object.

Doing so, you will always have the current user object within all authenticated routes.

First change your Auth middleware like so:

const auth = async (req, res, next) => {
    try {
        // Try to find user
        const token = req.header('Authorization').replace('Bearer ', '')
        const decoded = jwt.verify(token, 'thejwtsecret')
        const user = await User.findOne({ _id: decoded._id, 'tokens.token': token }) 

        // If user not found, throw error
        if (!user) {
            throw new Error()
        }

        // Else, add user data and toke into request object
        req.token = token
        req.user = user
        
        // Keep going
        next()
    } catch (e) {
        // User not authenticated
        res.status(401).send({ error: 'Please authenticate.' })
    }
}
module.exports = auth

You said you have a Sauces collection, and a delete route, with this new middleware the user data will be easily accessible inside the request object:

router.delete('/sauces', auth, async (req, res) => {
    // req.user is your current user object 
    // req.token is the token of the current user
});