密码重置令牌GET请求无效

时间:2018-01-12 10:56:29

标签: javascript node.js express passport.js passport-local

编辑#2

我做了以下更改

在邮件中我已经改变

text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + 'http://' + req.headers.host + '/reset-password/' + token + '\n\n' + 'If you did not request this, please ignore this email and your password will remain unchanged.\n'

text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + 'http://' + req.headers.host + '/users/reset-password/' + token + '\n\n' + 'If you did not request this, please ignore this email and your password will remain unchanged.\n'

和我的路线来自

// Reset Password Token link :get
router.get('/reset-password/:token', function(req, res) {

// Reset Password Token :post
router.post('/reset-password/:token', function(req, res, next) {

// Reset Password Token link :get
router.get('/users/reset-password/:token', function(req, res) {

// Reset Password Token :post
router.post('/users/reset-password/:token', function(req, res, next) {

我仍然在原始问题中收到GET错误。

enter image description here

编辑#1

app.js

const express = require('express');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const hbs = require('hbs');
const expressValidator = require('express-validator');
const flash = require('connect-flash');
const session = require('express-session');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const fs = require('fs');

var app = express();

// Server port
const port = process.env.PORT || 3000;
// Server starting message
app.listen(port, () => {
  console.log(`Server is up on port ${port}`);
});

// Views directory established and handbars engine
hbs.registerPartials(__dirname + '/views/layouts')
app.set('view engine', 'hbs');

// static assets rendered
app.use(express.static(__dirname + '/public'));
app.use('/users', express.static(__dirname + '/public'));
app.use('/dashboard', express.static(__dirname + '/public'));

// body-parser middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(cookieParser());

// expressSession
app.use(session({
  secret: 'secret',
  saveUninitialized: true,
  resave: true
}));

// passport
app.use(passport.initialize());
app.use(passport.session());

// expressValidator
app.use(expressValidator({
  errorFormatter: function(param, msg, value) {
    var namespace = param.split('.'),
    root = namespace.shift(),
    formParam = root;

    while(namespace.length) {
      formParam += '[' + namespace.shift() + ']';
    }

    return {
      param: formParam,
      msg: msg,
      value: value
    };
  }
}));

// Connect Flash
app.use(flash());

// Global Vars
app.use(function (req, res, next) {
  res.locals.success_msg = req.flash('success_msg');
  res.locals.error_msg = req.flash('error_msg');
  res.locals.error = req.flash('error');
  res.locals.user = req.user || null;
  next();
});

// server.log setup middleware
app.use((req, res, next) => {
  var now = new Date().toString();
  var log = `${now}: ${req.method} ${req.url}`

  console.log(log);

  fs.appendFile('server.log', log + '\n', (err) => {
    if (err) {
      console.log('Unable to append to server.log');
    }
  });
  next();
});

// Routes
const routes = require('./routes/routes');
const users = require('./routes/users');
const dashboard = require('./routes/dashboard');
app.use("/", routes);
app.use("/users", users);
app.use("/dashboard", dashboard);

// Get year for footer
hbs.registerHelper('getCurrentYear', () => {
  return new Date().getFullYear()
});

- 原始问题

我尝试使用以下tutorial

在我的应用中实施密码重置功能

我做了一些调整以满足我的需求和我想要的路线,但目前我得到了以下内容

enter image description here

-

这是我当前的文件结构

enter image description here

这是我当前的代码

user.js型号

const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

var app = express();

if (app.get('env') === 'production') {
  mongoose.connect(process.env.DATABASE_URL, { useMongoClient: true });
} else {
  mongoose.connect('mongodb://localhost/pol-development', { useMongoClient: true });
}

var db = mongoose.connection;

db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
  console.log("Connection has been established");
});

var UserSchema = mongoose.Schema({
  schoolName: String,
  schoolAddress: String,
  schoolAddress2: String,
  city: String,
  zipCode: String,
  addressCheck: Boolean,
  postalAddress: String,
  postalCity: String,
  postalZipCode: String,
  telephone: Number,
  fax: Number,
  email: { type: String, required: true, unique: true },
  password: String,
  schoolType: String,
  schoolDistrict: String,
  schoolRegion: String,
  curriculum: String,
  participationBefore: Boolean,
  participationYears: Number,
  directorName: String,
  directorTelephone: Number,
  directorEmail: String,
  directorAttendanceRehersal: Boolean,
  directorAttendanceEvent: Boolean,
  schoolLiaisonName: String,
  schoolLiaisonTelephone: Number,
  schoolLiaisonEmail: String,
  schoolLiaisonPosition: String,
  schoolLiaisonOtherPosition: String,
  schoolLiaisonTShirt: String,
  schoolLiaisonTutorMentor: String,
  attendanceRehersal: Boolean,
  attendanceEvent: Boolean,
  admin: Boolean,
});

UserSchema.pre('save', function(next) {
  var user = this;
  var SALT_FACTOR = 5;

  if (!user.isModified('password')) return next();

  bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
    if (err) return next(err);

    bcrypt.hash(user.password, salt, null, function(err, hash) {
      if (err) return next(err);
      user.password = hash;
      next();
    });
  });
});

var User = module.exports = mongoose.model('User', UserSchema);

module.exports.createUser = function(newUser, callback){
  bcrypt.genSalt(10, function(err, salt) {
    bcrypt.hash(newUser.password, salt, function(err, hash) {
      newUser.password = hash;
      newUser.save(callback);
    });
  });
}

module.exports.getUserByEmail = function(email, callback){
  var query = {email: email};
  User.findOne(query, callback);
}

module.exports.getUserById = function(id, callback){
  User.findById(id, callback);
}

module.exports.comparePassword = function(candidatePassword, hash, callback) {
  bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
    if(err) throw err;
    callback(null, isMatch);
  });
}

users.js路线

const express = require('express');
const router = express.Router();
const passport = require('passport');
const nodemailer = require('nodemailer');
const randomBytes = require('randombytes');
const async = require('async');
const LocalStrategy = require('passport-local').Strategy;

var User = require('../models/user');

// Register :get
router.get('/register', (req, res) => {
  res.render('register.hbs', {
    pageTitle: 'Register'
  });
});

// Register :post
router.post('/register', (req, res) => {
  var schoolName = req.body.schoolName;
  var schoolAddress = req.body.schoolAddress;
  var schoolAddress2 = req.body.schoolAddress2;
  var city = req.body.city;
  var zipCode = req.body.zipCode;
  var postalAddress = req.body.postalAddress;
  var postalCity = req.body.postalCity;
  var postalZipCode = req.body.postalZipCode;
  var telephone = req.body.telephone;
  var email = req.body.email;
  var password = req.body.password;
  var schoolType = req.body.schoolType;
  var schoolDistrict = req.body.schoolDistrict;
  var schoolRegion = req.body.schoolRegion;
  var curriculum = req.body.curriculum;
  var directorName = req.body.directorName;
  var directorTelephone = req.body.directorTelephone;
  var directorEmail = req.body.directorEmail;
  var schoolLiaisonName = req.body.schoolLiaisonName;
  var schoolLiaisonTelephone = req.body.schoolLiaisonTelephone;
  var schoolLiaisonEmail = req.body.schoolLiaisonEmail;
  var schoolLiaisonPosition = req.body.schoolLiaisonPosition;
  var schoolLiaisonTShirt = req.body.schoolLiaisonTShirt;
  var schoolLiaisonTutorMentor = req.body.schoolLiaisonTutorMentor;

  // validations
  req.checkBody('schoolName', 'The school name is required').notEmpty();
  req.checkBody('schoolAddress', 'The school address is required').notEmpty();
  req.checkBody('city', 'The city is required').notEmpty();
  req.checkBody('zipCode', 'This zip code is required').notEmpty();
  req.checkBody('telephone', 'A telephone number is required').notEmpty();
  req.checkBody('email', 'An account email is required').notEmpty();
  req.checkBody('email', 'This account email is not valid').isEmail();
  req.checkBody('password', 'An account password is required').notEmpty();
  req.checkBody('schoolType', 'A school type is required').notEmpty();
  req.checkBody('schoolDistrict', 'A school district is required').notEmpty();
  req.checkBody('schoolRegion', 'A school region is required').notEmpty();
  req.checkBody('curriculum', 'A curriculum is required').notEmpty();
  req.checkBody('directorName', 'A directors name is required').notEmpty();
  req.checkBody('directorTelephone', 'A directors telephone is required').notEmpty();
  req.checkBody('directorEmail', 'A directors email is required').notEmpty();
  req.checkBody('directorEmail', 'This email is not valid').isEmail();
  req.checkBody('schoolLiaisonName', 'A school representative name is required').notEmpty();
  req.checkBody('schoolLiaisonTelephone', 'A school representative telephone is required').notEmpty();
  req.checkBody('schoolLiaisonEmail', 'The school representative email is not valid').isEmail();
  req.checkBody('schoolLiaisonEmail', 'A school representative email is required').notEmpty();
  req.checkBody('schoolLiaisonPosition', 'A school representative position is required').notEmpty();
  req.checkBody('schoolLiaisonTShirt', 'A school representative t-shirt size is required').notEmpty();
  req.checkBody('schoolLiaisonTutorMentor', 'A school representative tutor/mentor is required').notEmpty();

  var errors = req.validationErrors();

  if (errors) {
    res.render('register', {
      errors:errors
    });
  } else {
    var newUser = new User({
      schoolName: schoolName,
      schoolAddress: schoolAddress,
      schoolAddress2: schoolAddress2,
      city: city,
      zipCode: zipCode,
      postalAddress: postalAddress,
      postalCity: postalCity,
      postalZipCode: postalZipCode,
      telephone: telephone,
      email: email,
      password: password,
      schoolType: schoolType,
      schoolDistrict: schoolDistrict,
      schoolRegion: schoolRegion,
      curriculum: curriculum,
      directorName: directorName,
      directorTelephone: directorTelephone,
      directorEmail: directorEmail,
      schoolLiaisonName: schoolLiaisonName,
      schoolLiaisonTelephone: schoolLiaisonTelephone,
      schoolLiaisonEmail: schoolLiaisonEmail,
      schoolLiaisonPosition: schoolLiaisonPosition,
      schoolLiaisonTShirt: schoolLiaisonTShirt,
      schoolLiaisonTutorMentor: schoolLiaisonTutorMentor,
    });

    User.createUser(newUser, function(err, user) {
      if(err) throw err;
      console.log(user);
    });

    req.flash('success_msg', 'You are now registered, you can now login!');
    res.redirect('/users/login');
  }
});

passport.use(new LocalStrategy({
  usernameField: 'email'
  },
  function(email, password, done) {
    User.getUserByEmail(email, function(err, user){
      if(err) throw err;
      if(!user){
        return done(null, false, {message: 'Unknown Email Address'});
      }

      User.comparePassword(password, user.password, function(err, ismatch){
        if(err) throw err;
        if(ismatch){
          return done(null, user);
        } else {
          return done(null, false, {message: 'Invalid password'});
        }
      });
    });
  }));

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.getUserById(id, function(err, user) {
    done(err, user);
  });
});

// Login :get
router.get('/login', (req, res) => {
  res.render('login.hbs', {
    pageTitle: 'Login'
  });
});

// Login :post
router.post('/login', passport.authenticate('local', {
  successRedirect: '/dashboard',
  failureRedirect: '/users/login',
  successFlash: 'Welcome!',
  failureFlash: 'Invalid email or password.'
}), function(req, res) {
  // res.redirect('/' + req.user.username);
  res.redirect('/');
});

// Reset Password :get
router.get('/reset-password', function(req, res) {
  res.render('reset-password', {
    pageTitle: 'Reset Password',
    User: req.user
  });
});

// Reset Password :post
router.post('/reset-password', function(req, res, next) {
  async.waterfall([
    function(done) {
      randomBytes(20, function(err, buf) {
        var token = buf.toString('hex');
        done(err, token);
      });
    },
    function(token, done) {
      User.findOne({ email: req.body.email }, function(err, user) {
        if (!user) {
          req.flash('error', 'No account with that email address exists.');
          return res.redirect('/reset-password');
        }

        user.resetPasswordToken = token;
        user.resetPasswordExpires = Date.now() + 3600000; // 1 hour

        user.save(function(err) {
          done(err, token, user);
        });
      });
    },
    function(token, user, done) {
      nodemailer.createTestAccount((err, account) => {
        // create reusable transporter object using the default SMTP transport
        if (process.env.NODE_ENV === 'production') {
          transporter = nodemailer.createTransport({
            host: "smtp.sendgrid.net",
            port: 587,
            auth: {
              user: process.env.SENDGRID_USERNAME,
              pass: process.env.SENDGRID_PASSWORD,
            }
          });
        } else {
          transporter = nodemailer.createTransport({
            host: "smtp.ethereal.email",
            port: 587,
            auth: {
              user: 'qkkvnabtziufbksa@ethereal.email',
              pass: 'A4W9HF2WbhAav263VM',
            }
          });
        }
        // setup email data with unicode symbols
        let mailOptions = {
          from: 'password.reset' + process.env.GLOBAL_EMAIL || 'ben@benbagley.co.uk', // sender address
          to: user.email, // list of receivers
          subject: 'Reset Password Request', // Subject line
          text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + 'http://' + req.headers.host + '/reset-password/' + token + '\n\n' + 'If you did not request this, please ignore this email and your password will remain unchanged.\n' // output
        };
        // send mail with defined transport object
        transporter.sendMail(mailOptions, (error, info) => {
          req.flash('success', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
          done(err, 'done');
          res.redirect('/users/reset-password');
        });
      });
    }
  ], function(err) {
    if (err) return next(err);
    res.redirect('/');
  });
});

// Reset Password Token link :get
router.get('/reset-password/:token', function(req, res) {
  User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
    if (!user) {
      req.flash('error', 'Password reset token is invalid or has expired.');
      return res.redirect('/users/reset-password');
    }

    res.render('/', {
      user: req.user
    });
  });
});

// Reset Password Token :post
router.post('/reset-password/:token', function(req, res, next) {
  async.waterfall([
    function(done) {
      User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
        if (!user) {
          req.flash('error', 'Password reset token is invalid or has expired.');
          return res.redirect('back');
        }

        user.password = req.body.password;
        user.resetPasswordToken = undefined;
        user.resetPasswordExpires = undefined;

        user.save(function(err) {
          req.logIn(user, function(err) {
            done(err, user);
          });
        });
      });
    },
    function(user, done) {
      nodemailer.createTestAccount((err, account) => {
        // create reusable transporter object using the default SMTP transport
        if (process.env.NODE_ENV === 'production') {
          transporter = nodemailer.createTransport({
            host: "smtp.sendgrid.net",
            port: 587,
            auth: {
              user: process.env.SENDGRID_USERNAME,
              pass: process.env.SENDGRID_PASSWORD,
            }
          });
        } else {
          transporter = nodemailer.createTransport({
            host: "smtp.ethereal.email",
            port: 587,
            auth: {
              user: 'qkkvnabtziufbksa@ethereal.email',
              pass: 'A4W9HF2WbhAav263VM',
            }
          });
        }
        // setup email data with unicode symbols
        let mailOptions = {
          from: 'password.reset' + process.env.GLOBAL_EMAIL || 'ben@benbagley.co.uk', // sender address
          to: user.email, // list of receivers
          subject: 'Your password has been changed', // Subject line
          text: 'Hello,\n\n' + 'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n' // output
        };
        // send mail with defined transport object
        transporter.sendMail(mailOptions, (err) => {
          req.flash('success', 'Success! Your password has been changed.');
          done(err);
        });
      });
    }
  ], function(err) {
    res.redirect('/');
  });
});

// Logout
router.get('/logout', function(req, res) {
  req.logout();
  req.flash('success_msg', 'You are now logged out!');
  res.redirect('/users/login');
});

module.exports = router;

new-password

{{> header }}

<div class="container">
    {{> flash }}

    <form action="/users/reset-password" method="post">
        <div class="panel panel-default">
            <div class="panel-heading">Reset Password</div>

            <div class="panel-body">
                <div class="form-group">
                    <label for="exampleInputEmail1">New Password</label>
                    <input type="password" class="form-control" placeholder="New Password" name="password" value="">
                </div>

                <div class="form-group">
                    <label for="exampleInputEmail1">Confirm Password</label>
                    <input type="password" class="form-control" placeholder="Confirm Password" name="confirm" value="">
                </div>
                <button type="submit" class="btn btn-primary">Update Password</button>
            </div><!-- Panel Body -->
        </div><!-- Panel Default -->
    </form>
</div><!-- Container ends -->

{{> footer }}

任何帮助都将不胜感激。

这里的预期

点击电子邮件中的链接后,令牌会被传递,并将用户重定向到新密码页面,以便他们可以更改密码。

不确定还有什么可以尝试。

1 个答案:

答案 0 :(得分:0)

你有这个:

const users = require('./routes/users');
app.use("/users", users);

并且在您的users.js中有这个。

router.post('/reset-password/:token', function(req, res, next) {

您正尝试访问:

`localhost:3000/reset-password/sdasdasdtokenblabla`

你应该去:

`localhost:3000/users/reset-password/tokenblabla`