Токен JWT не может быть установлен в заголовок (узел

#node.js #express #mongodb-query

Вопрос:

Я работаю над серверной частью узла, которая использует MongoDB в качестве своей базы данных. Когда я должен отправить свой токен JWT в заголовке ответа, я получаю сообщение об ошибке, что заголовки не могут быть установлены после их отправки клиенту. Вот мой почтовый запрос:

 api.post("/account/create", async (req, res) => {

    // Hash the password using bcrypt
    const hashedPassword = await bcrypt.hash(req.body.password, 10);

    // Store new login credentials
    const user = {
        username: req.body.username,
        password: hashedPassword
    };

    // Create a new JWT token
    const token = jwt.sign({ username: req.body.username }, secret);

    // Search for a matching username from the database
    await logincollection.findOne(user, (err, result) => {

        // If username was not found, add the credentials to the database
        if (result == null) {

            // Insert the credentials to the login credentials collection
            logincollection.insertOne(user, (err, result) => {

                // If an error occurred, return code 404 to the client
                if (err) {
                    res.status(404).send();
                }

            })

            // Create personal collection for the user
            userdb.createCollection(JSON.stringify(user.username), (err, result) => {

                // If an error occurred, return code 404 to the client
                if (err) {
                    res.status(404).send();
                }

            })

            // Return code 200 (success)
            res.status(200).send({ auth: true, token: token });

        } else {

            // If username was found, return code 400 to the client
            res.status(400).send();

        }

    })

})
 

Когда я пытаюсь получить значение токена в другом запросе POST, он возвращает undefined :

 api.post("/account/login", async (req, res) => {

    // User object
    const user = {
        username: req.body.username,
        password: req.body.password
    };

    const token = req.headers["token"];
    console.log(token);

    // Get username as a string
    const username = JSON.stringify(user.username);

    // Get hashed password from the collection
    const hashedPassword = await logincollection.findOne({ username: req.body.username });
    console.log(hashedPassword);

    // Search for matching login credentials
    await logincollection.find(user, (err, result) => {

        // If no token was given
        if (!token) {

            // Return code 401 to the client
            res.status(401).send();

        }

        // Verify the given JWT token
        jwt.verify(token, secret, (err, decoded) => {

            // If verification failed
            if (err) {

                // Return code 500 to the client
                res.status(500).send();

            }

            // Return code 200 and decoded token to the client
            res.status(200).send(decoded);

        })

            // Use bcrypt to compare the passwords and authenticate login
            bcrypt.compare(req.body.password, hashedPassword).then(match => {

                // If the credentials match
                if (match) {

                    // Return the result as an object
                    const sendObject = {
                        username: result.username,
                        password: result.password
                    };

                    // Return code 200 to the client
                    res.status(200).send(sendObject);

                    // Log to console when user logs in
                    console.log("User "   username   " logged in");

                // If the credentials do not match
                } else {

                    // Return code 404 to the client
                    res.status(404).send();

                }

            // If comparing fails
            }).catch(error => {

                // Return coe 500 to the client
                res.status(500).send();

            })

    })

})
 

Я почти уверен, что решение-это что-то невероятно простое, но я просто не могу решить эту проблему, хотя я уже провел много исследований.

Вот ответ, возвращенный клиенту из запроса /учетная запись/создать:

 {
    "auth": true,
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QyIiwiaWF0IjoxNjMzNzg3MjE2fQ.duo5R9wXpk2Gj-iPHFMaDgKK0p3h6WZf5vnXrZViePo"
}
 

ИЗМЕНИТЬ: Оказывается, что токен переходит не в заголовок, а в тело. Что мне нужно сделать по-другому, чтобы передать его в заголовок?

Комментарии:

1. вы уверены, что результат вызова API «/учетная запись/создать» со статусом 200 вернет токен правильно?

2. пожалуйста, поделитесь своими кодами на стороне клиента, которые связаны с установкой токена в заголовке. вы также можете проверить это на вкладке сеть chrome, проверив вызов API и проверив его заголовок. правильно ли прикреплен и отправлен токен с помощью вызовов API?

3. @novonimo Я внес некоторые изменения в вопрос, включая оставшуюся часть запроса на вход и ответ, данный запросом /учетная запись/создать

4. как я уже упоминал ранее, пожалуйста, добавьте связанный с клиентом код

5. @novonimo Что вы подразумеваете под кодом, связанным с клиентом? Интерфейс для этого-приложение для Android, вы имеете в виду этот код?

Ответ №1:

В этом result == null случае у вас есть три инструкции, которые отправляют ответ: две асинхронные res.status(404) инструкции и одна синхронная res.status(200) инструкция. Только из них могут быть выполнены по запросу.

Но в текущем коде оператор status 200 выполняется для каждого запроса, даже если неудачная операция с базой данных позже приводит к дополнительному оператору status 404, который затем вызывает наблюдаемую ошибку.

Комментарии:

1. Я изменил код так, чтобы код ответа 200 возвращался только после успешного завершения всех операций с базой данных, но конечный результат тот же.

Ответ №2:

Ладно, похоже, я понял это неправильно.

Я думал, что токен всегда должен быть возвращен и получен в заголовке. Это не тот случай. Ответ токена от /учетная запись/создать должен быть в теле. Токен должен быть установлен только в заголовок при запуске запроса /учетная запись/вход (аутентификация входа).

Надеюсь, это может помочь кому-то, у кого в будущем возникнет тот же вопрос.