首页 > 解决方案 > 在 Typeorm SQL 中使用 Node、Express、JWT 重置密码

问题描述

我的密码重置功能 ( changepass) 有问题,这可能是我的代码的一个小错误。

通过 nodemailer 处理新密码并成功登录后,我尝试实现允许用户更新密码的下一个功能。

用户登录后,我的身份验证中间件在所有其他功能中都能正常工作。

登录后,我在正文上提交旧密码和新密码,在Bearer Token字段中提交新令牌。令人惊讶的是,我得到了状态 204,因为它一直有效。

在终端上,我不断收到以下信息:

  1. const id = res.locals.userId; -> undefined;
  2. No metadata found. There is more than once class-validator version installed probably. You need to flatten your dependencies.

该功能确实做了一些事情,但是它无法再用旧密码和新密码登录,所以我需要再次通过nodemailer请求新密码。

有人知道我的错误在哪里吗?


密码重置(问题出在哪里):

async changepass(req: Request, res: Response) {
    // Get ID from JWT
    const id = res.locals.userId;
    console.log(id)
    // Get parameters from the body
    const { oldPassword, newPassword } = req.body;

    if (!(oldPassword && newPassword)) {
        res.status(400).send();
    }

    // Get user from the database
    const userRepository = getRepository(User);
    // let user = await userRepository.findOneOrFail(id);
    let user = User as any;
    try {
        user = await userRepository.findOneOrFail(id);
    } catch (id) {
        res.status(401).send();
    }

    // Check if old password matches
    if (!user.checkIfUnencryptedPasswordIsValid(oldPassword)) {
        res.status(401).send();
        return;
    }

    // Validate the model (Password length)
    user.password = newPassword;
    const errors = await validate(user);
    if (errors.length > 0) {
        res.status(400).send(errors);
        return;
    }
    // Hash the new password and save
    user.hashPassword();
    userRepository.save(user);

    res.status(204).send();
},

用户登录:

async login(req: Request, res: Response) {
    // Get user from database
    const userRepository = getRepository(User);
    const { email, password } = req.body;

    // Check if useremail and password are set
    if (!(email && password)) {
        console.error('Empty name or password!');
        return res.status(400).send({
            error: 'Empty name or password'
        });
    }
    
    const user = await userRepository.findOne({ where: { email } });

    if(!user) {
        return res.sendStatus(401);
    }
    
    // Check if encrypted password match : checkIfUnenc... função vemm do model
    if (!user.checkIfUnencryptedPasswordIsValid(password)) {
        return res.status(401).send({
            error: 'Cannot match encrypted password'
        });
    }     
    
    // Sing JWT, valid for 1 hour
    const token = jwt.sign(
        { id: user.id, email: user.email }, //payload do token, informações do user
        config.jwtSecret, //chave secreta que autoriza, ideal no .env
        { expiresIn: "1d" }
    );
    
    // Send the jwt in the response
    res.json({
        user,
        token
    });
},

路线:

//change password route
routes.post('/users/changepass', checkJwt, UserController.changepass);

认证中间件:

interface TokenPayload {
    id: number;
    iat: string;
    exp: string;
}

export default function checkJwt(req: Request, res: Response, next: NextFunction) {

    const { authorization } = req.headers;
    // console.log(authorization)

    if(!authorization) {
        return res.sendStatus(401)
    }

    const token = authorization.replace("Bearer", "").trim(); //apenas remover a palavra "Bearer" e espaço

    try {
        const data = jwt.verify(token, config.jwtSecret)
        //console.log(data) -> data traz no log o id, iat, exp, então tenho que tipar o data com interface

        const { id } = data as TokenPayload; 
    
        req.userId  = id;  
        console.log(id)
    } catch {
        return res.sendStatus(401);
    }
    next();
}

标签: node.jstypescriptjwtnodemailer

解决方案


推荐阅读