使用passportjs重置/更改nodejs中的密码

我在nodejs中使用passportjs来创build一个login系统。 一切正常,但我不知道如何重置用户密码,当他们忘记密码或他们想改变它。

MongoDB中的用户模型

var UserSchema = new Schema({ email: String, username: String, provider: String, hashed_password: String, salt: String, }); 

提前致谢!

有没有真正喜欢打我的数据库存储令牌的想法,尤其是当你想创build和validation令牌许多行动。

相反,我决定复制Django如何做到这一点 :

  • today一样将timestamp_today转换为base36
  • 将user.id转换为base36作为ident
  • 创buildhash包含:
    • timestamp_today
    • 用户名
    • user.last_login
    • 用户密码
    • user.email
  • 用一个隐藏的秘密来encryption哈希
  • 创build一个如下所示的路由:/ change-password / :ident / :today:hash

我们testingreq.params.timestamp是为了简单地testing它是否适用于今天,最便宜的testing。 首先失败。

然后我们find用户,如果不存在则失败。

然后我们再次从上面生成哈希,但是从req.params中获得时间戳

在以下情况下,重置链接将失效

  • 他们记住他们的密码和login(last_login更改)
  • 他们实际上仍然login和:
    • 只需更改密码(密码更改)
    • 只要改变他们的电子邮件
  • 明天到来(时间戳变化太多)

这条路:

  • 你不会把这些短暂的东西存储在你的数据库中
  • 当令牌的目的是改变事物的状态,并且事物状态改变时,则令牌的目的不再安全地相关。

我试图使用节点密码重置作为Matt617build议,但并不真正关心它。 这是目前唯一的search。

所以有几个小时挖掘,我发现自己实现这个更容易。 最后,我花了大约一天的时间来获取所有的路线,用户界面,电子邮件和一切工作。 我仍然需要增强安全性(重置计数器以防止滥用等),但基本工作:

  1. 创build了两个新的路由,/忘记和/重置,这不需要用户login访问。
  2. 一个GET /忘记显示一个用户界面,只有一个input的电子邮件。
  3. POST /忘记检查是否有用户使用该地址并生成随机令牌。
    • 用令牌和失效date更新用户的logging
    • 发送带有/ reset / {token}链接的电子邮件
  4. GET on / reset / {token}检查是否有一个用户没有过期的令牌,然后用新的密码input显示UI。
  5. POST on / reset(发送新的pwd和令牌)检查是否有一个用户没有过期的令牌。
    • 更新用户的密码。
    • 将用户的令牌和有效期设置为空

这里是我的代码生成一个令牌(取自节点密码重置):

 function generateToken() { var buf = new Buffer(16); for (var i = 0; i < buf.length; i++) { buf[i] = Math.floor(Math.random() * 256); } var id = buf.toString('base64'); return id; } 

希望这可以帮助。

编辑:这是app.js。 注意我将整个用户对象保留在会话中。 我打算将来转移到couchbase或类似的地方。

 var express = require('express'); var path = require('path'); var favicon = require('static-favicon'); var flash = require('connect-flash'); var morgan = require('morgan'); var cookieParser = require('cookie-parser'); var cookieSession = require('cookie-session'); var bodyParser = require('body-parser'); var http = require('http'); var https = require('https'); var fs = require('fs'); var path = require('path'); var passport = require('passport'); var LocalStrategy = require('passport-local').Strategy; var app = express(); app.set('port', 3000); app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); var cookies = cookieSession({ name: 'abc123', secret: 'mysecret', maxage: 10 * 60 * 1000 }); app.use(cookies); app.use(favicon()); app.use(flash()); app.use(morgan()); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(cookieParser()); app.use(passport.initialize()); app.use(passport.session()); app.use(express.static(path.join(__dirname, 'public'))); module.exports = app; passport.use(new LocalStrategy(function (username, password, done) { return users.validateUser(username, password, done); })); //KEEP ENTIRE USER OBJECT IN THE SESSION passport.serializeUser(function (user, done) { done(null, user); }); passport.deserializeUser(function (user, done) { done(null, user); }); //Error handling after everything else app.use(logErrors); //log all errors app.use(clientErrorHandler); //special handler for xhr app.use(errorHandler); //basic handler http.createServer(app).listen(app.get('port'), function () { console.log('Express server listening on HTTP port ' + app.get('port')); }); 

编辑:这里是路线。

 app.get('/forgot', function (req, res) { if (req.isAuthenticated()) { //user is alreay logged in return res.redirect('/'); } //UI with one input for email res.render('forgot'); }); app.post('/forgot', function (req, res) { if (req.isAuthenticated()) { //user is alreay logged in return res.redirect('/'); } users.forgot(req, res, function (err) { if (err) { req.flash('error', err); } else { req.flash('success', 'Please check your email for further instructions.'); } res.redirect('/'); }); }); app.get('/reset/:token', function (req, res) { if (req.isAuthenticated()) { //user is alreay logged in return res.redirect('/'); } var token = req.params.token; users.checkReset(token, req, res, function (err, data) { if (err) req.flash('error', err); //show the UI with new password entry res.render('reset'); }); }); app.post('/reset', function (req, res) { if (req.isAuthenticated()) { //user is alreay logged in return res.redirect('/'); } users.reset(req, res, function (err) { if (err) { req.flash('error', err); return res.redirect('/reset'); } else { req.flash('success', 'Password successfully reset. Please login using new password.'); return res.redirect('/login'); } }); }); 

在你的数据库中创build一个随机的重置键,用时间戳记坚持。 然后创build一个接受重置键的新路线。 在将密码更改为路由中的新密码之前validation时间戳。

从来没有试过这个,但我跑了这个前一段时间,这是类似于你所需要的: https : //github.com/substack/node-password-reset

Interesting Posts