繁体   English   中英

Node.js 中的密码重置令牌无效或已过期

[英]Password reset token is invalid or has been expired in Node.js

又是我在 Nodejs 中寻求帮助。 我尝试处理我使用 Postman 在 Nodejs 上创建的 resetPassword function,但我一直遇到同样的错误。 我还从我的 MongoDB Compass 中注意到,数据库上的 resetPasswordToken 和使用 mailtrap 发送的 resetPasswordToken 不一样。 这是我的代码:

//user.js
const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const crypto = require('crypto')

const userSchema = new mongoose.Schema({
    name:{
        type: String,
        required: [true, 'Please enter your name'],
        maxLength: [30, 'Your name cannot exceed 30 characters']
    },
    email:{
        type: String,
        required: [true, ' Please enter your email'],
        unique: true,
        validate:[validator.isEmail, 'Please enter a valid email address.']
    },
    password:{
        type:String,
        required: [true, 'Please enter your password'],
        minlength: [6, 'Your password must be longer that 6 characters.'],
        select: false
    },
    role:{
        type: String,
        default: 'admin'
    },
    createdAt: {
        type: Date,
        default:Date.now
    },
    resetPasswordToken: String,
    resetPasswordExpire: Date
})
//Encrypting password before saving user
userSchema.pre('save',async function(next){
    if(!this.isModified('password')){
        next()
    }
    this.password = await bcrypt.hash(this.password, 10)
})

//Compare user password
userSchema.methods.comparePassword = async function(enteredPassword){
    return await bcrypt.compare(enteredPassword, this.password)
}

//Return JWT token
userSchema.methods.getJwtToken = function(){
    return jwt.sign({id:this._id}, process.env.JWT_SECRET,{
        expiresIn: process.env.JWT_EXPIRES_TIME
    })
}
// Generate password reset token
userSchema.methods.getResetPasswordToken = function(){
    //Generate token
    const resetToken = crypto.randomBytes(20).toString('hex');

    //Hash and set to resetPasswordToken
    this.resetPasswordToken = crypto.createHash('sha256').update(resetToken).digest('hex')

    //Set token expire time
    this.resetpasswordExpire = Date.now() + 30 * 60 * 1000

    return resetToken
}

module.exports = mongoose.model('User', userSchema);
//authController.js
const User = require('../models/user')

const ErrorHandler = require('../utils/errorHandler');
const catchAsyncErrors = require('../middlewares/catchAsynchErrors');
const sendToken = require('../utils/jwtToken');
const sendEmail = require('../utils/sendEmail')

const crypto = require('crypto')

//Register a user => /api/v1/register
exports.registerUser = catchAsyncErrors (async (req, res, next) =>{

    const { name, email, password } =req.body;

    const user = await User.create({
        name,
        email,
        password
    })

    sendToken(user, 200, res)
})

//Login User  => api/v1/login
exports.loginUser = catchAsyncErrors (async (req,res,next) =>{
    const { email, password} = req.body;

    //Checks if email and password is entered by user
    if(!email || !password){
        return next(new ErrorHandler('Please enter email and password', 400))
    }
    //Finding the user in database
    const user = await User.findOne({email}).select('+password')

    if(!user){
        return next(new ErrorHandler('Invalid Email or Password', 401));
    }

    //Checks if password or correct or not
    const isPasswordMatched = await user.comparePassword(password)

    if (!isPasswordMatched) {
        return next(new ErrorHandler('Invalid Email or Password', 401));
    }
    sendToken(user,200,res)
})
//Forgot Password => api/v1/password/forgot
exports.forgotPassword = catchAsyncErrors(async(req, res, next) => {

    const user = await User.findOne({email: req.body.email});

    if(!user){
        return next(new ErrorHandler('User not found', 404));
    }
    //Get reset token
    const resetToken = user.getResetPasswordToken();

    await user.save({validateBeforeSave: false })

    //Create reset password url
    const resetUrl =`${req.protocol}://${req.get('host')}/api/v1/password/reset/${resetToken}`;
    
    const message = `Your password reset token is as follows:\n\n${resetUrl}\n\n If you have not requested this email, then please ignore.`

    try{

        await sendEmail({
            email: user.email,
            subject: "KPOPStore Password Recovery",
            message
        })
        
        res.status(200).json({
            success: true,
            message: `Email sent to ${user.email}`
        })
    }catch (error){
        user.resetPasswordToken = undefined;
        user.resetPasswordExpire = undefined;

        await user.save({validateBeforeSave: false })

        return next(new ErrorHandler(error.message, 500))
 
    }
})
//ResetPassword => /api/v1/password/reset/:token
exports.resetPassword = catchAsyncErrors(async(req, res, next) =>{

    //Hash URL Token
    const resetPasswordToken = crypto.createHash('sha256').update(req.params.token).digest('hex')

    const user = await User.findOne({
        resetPasswordToken,
        resetPasswordExpire: { $gt: Date.now() }

    })
    if(!user){
        return next(new ErrorHandler('Password reset token is invalid or has been expired.', 400)
        )
    }

    if(req.body.password !== req.body.confirmPassword){
        return next(new ErrorHandler('Password does not match', 400))
    }
    //Setup new password
    user.password = req.body.password;

    user.resetPasswordToken = undefined;
    user.resetPasswordExpire = undefined;

    await user.save();

    sendToken(user, 200, res)
})
//Logout user => /api/v1/logout
exports.logout = catchAsyncErrors(async (req,res,next)=>{
    res.cookie('token', null, {
        expires: new Date(Date.now()),
        httpOnly: true
    })
    res.status(200).json({
        success: true,
        message: 'Logged out'
    })
})
//jwtToken.js
//Create and send token and save in cookie.
const sendToken =( user, statusCode, res)=>{

    //Create Jwt token
    const token = user.getJwtToken();

    //Options for cookie
    const options = {
        expires: new Date(
            Date.now() + process.env.COOKIE_EXPIRES_TIME * 24 * 60 * 60 * 1000
        ),
        httpOnly: true
    }

    res.status(statusCode).cookie('token', token, options).json({
        success: true,
        token,
        user
    })
}
module.exports = sendToken;
//auth.js
const express = require('express');
const router = express.Router();

const { registerUser, loginUser, logout, forgotPassword, resetPassword} = require('../controllers/authController')

router.route('/register').post(registerUser);
router.route('/login').post(loginUser);

router.route('/password/forgot').post(forgotPassword)
router.route('/password/reset/:token').put(resetPassword)


router.route('/logout').get(logout);

    
module.exports = router;

对于长长的代码块,我很抱歉。 我已经被困在这部分3天了。 请再次帮助我。 谢谢!

这是用户模型方法中的一个错字:

//Set token expire time
    this.resetpasswordExpire = Date.now() + 30 * 60 * 1000

它设置resetpasswordExpire ,而不是resetPasswordExpire ,因此对象-文档映射器不会拾取更改,也不会保存在数据库中。 然后,您的搜索失败:

User.findOne({
        resetPasswordToken,
        resetPasswordExpire: { $gt: Date.now() }

    })

因为未设置 resetPasswordExpire。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM