【问题标题】:Authentication with bcrypt and jwt does not work使用 bcrypt 和 jwt 的身份验证不起作用
【发布时间】:2021-03-17 05:15:00
【问题描述】:

我对 Node.js / Express 和 Web 应用程序的开发还很陌生。我尝试做一个简单的用户注册,在将哈希保存到 mongodb 之前,我使用 bcrypt 对密码进行哈希处理。应该允许用户登录的登录表单随后会在数据库中查找用户,然后比较两个密码。

我确实想保护我的网络应用程序中的某些路由,以便只有经过身份验证的用户才能访问它们。因此,当成功登录时,我确实沿响应标头发送了一个 Json Web 令牌(jwt),然后应该使用该响应标头 - 当重定向到受保护的“/大厅”路由时 - 对用户进行身份验证并允许他/她继续使用该路由.

但是,我总是收到以下错误:

错误 [ERR_HTTP_HEADERS_SENT]:发送到客户端后无法设置标头

所以看起来它在尝试设置标头之前已经向客户端发回了响应,这当然不再可能了。

非常感谢您的帮助!

我确实使用以下代码:

注册功能

async function register(req, res) {
    //Check with user already exists
    const  emailExists = await User.findOne({email: req.body.email});
    if(emailExists) {
        return res.status(400).send('User already exists!');
    };
    //Hash the password and create new user from request data
    bcrypt.hash(req.body.password, 10, async function (err, hashedPass){
        if(err){
            res.json({
                error: err
            });
        }
        let user = new User({
            name: req.body.name,
            email: req.body.email,
            username: req.body.username,
            password: hashedPass,
            password2: hashedPass
        });
        try {
            await user.save();
        }catch (err) {
            res.status(400).send(err);
        };
    });
    res.render('index');
};

登录功能

async function login(req, res) {
    const user = await User.findOne({email: req.body.email});
    if(!user) {
        return res.status(400).json({message: 'User not found!'}).render('index');
    };
    bcrypt.compare(req.body.password, user.password).then((result)=> {
        if(result){
            const token = jwt.sign({_id: user._id}, process.env.TOKEN_SECRET);
            res.setHeader('auth-token', token.toString());
            res.redirect('/lobby');
        }else {
            return res.status(400).json({message: 'Passwords do not match!'}).render('index');
        }
    }).catch((err)=> {
        console.log(err);
    });
};

作为 '/lobby' 路由的中间件(即当有人向 '/lobby' 发出 get 请求时),我使用了一个“verifyToken”函数,它应该确保通过 jwt 对用户进行正确的身份验证。

验证令牌函数

const jwt = require('jsonwebtoken');

module.exports = function(req, res, next) {
    console.log('verify function started');
    const token = req.header('auth-token');
    console.log(token);
    if(!token) {
        res.status(401).json({
            message: 'Access denied!'
        });
    };
    try {
        const verified = jwt.verify(token, process.env.TOKEN_SECRET);
        req.user = verified;
        next();
    }catch (err) {
        res.status(400).json({
            message: 'Invalid token!'
        });
    };
};

如前所述,我非常感谢您在这里的帮助!我认为问题比我想象的要简单得多:-)。

干杯

【问题讨论】:

  • 为什么需要res.render('index')?,如果是成功响应,则需要移入register function
  • 我不确定res.status(400).json({message: 'Passwords do not match!'}).render('index')json() 之后调用render。我从来没有见过,我们可以这样做吗?而且bcrypt 没有问题

标签: node.js express jwt bcrypt


【解决方案1】:

在少数情况下,您忘记了return 的回复。因此它还会继续执行其他代码,这就是服务器尝试再次发送响应的地方,这就是您收到该错误的原因。

如下更改您的回复。

验证令牌函数

const jwt = require('jsonwebtoken');

module.exports = function(req, res, next) {
    console.log('verify function started');
    const token = req.header('auth-token');
    console.log(token);
    if(!token) {
        return res.status(401).json({ // <-- here you need to `return`
            message: 'Access denied!'
        });
    };
    try {
        const verified = jwt.verify(token, process.env.TOKEN_SECRET);
        req.user = verified;
        next();
    }catch (err) {
        return res.status(400).json({
            message: 'Invalid token!'
        });
    };
};

注册功能

async function register(req, res) {
    //Check with user already exists
    const  emailExists = await User.findOne({email: req.body.email});
    if(emailExists) {
        return res.status(400).send('User already exists!');
    };
    //Hash the password and create new user from request data
    bcrypt.hash(req.body.password, 10, async function (err, hashedPass){
        if(err) {
            return res.json({ // <-- here as well
                error: err
            });
        }
        let user = new User({
            name: req.body.name,
            email: req.body.email,
            username: req.body.username,
            password: hashedPass,
            password2: hashedPass
        });
        try {
            await user.save();
            return res.render('index'); // <-- assuming this is your success response
        }catch (err) {
            return res.status(400).send(err); <-- here too
        };
    });
};

【讨论】:

    【解决方案2】:

    看起来像在 登录功能 中设置了标题。我可以通过console.log(res.header('auth-token')); 看到这一点。随后重定向到“/lobby”被调用,因为 verifyToken 函数 确实启动了。

    但是,在 verifyToken 函数 中,相应的标头是 undefined。因为我也经常收到'Access denied!' 消息。

    如前所述,在向 /lobby 路由发出 get 请求时,我确实将 verifyToken 函数调用为中间件。 '/lobby' 的路线如下所示:

    const express = require('express');
    const router = express.Router();
    const lobbyCtrl = require('../controllers/lobby');
    const verify = require('./verifyToken');
    
    router.get('/', verify, lobbyCtrl.display);
    
    module.exports = router;
    

    【讨论】:

      猜你喜欢
      • 2019-06-06
      • 2020-01-25
      • 2021-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-20
      • 2020-02-09
      相关资源
      最近更新 更多