编辑#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错误。
编辑#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
在我的应用中实施密码重置功能我做了一些调整以满足我的需求和我想要的路线,但目前我得到了以下内容
-
这是我当前的文件结构
这是我当前的代码
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 }}
任何帮助都将不胜感激。
这里的预期
点击电子邮件中的链接后,令牌会被传递,并将用户重定向到新密码页面,以便他们可以更改密码。
不确定还有什么可以尝试。
答案 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`