【问题标题】:How to add "Remember Me" to my app with passport如何使用护照将“记住我”添加到我的应用程序
【发布时间】:2013-03-25 06:51:18
【问题描述】:

this 这样登录时,我需要一个“记住我”复选框。 我在使用护照之前添加了一个中间件

app.use(function(req, res, next) {
  if (req.method == 'POST' && req.url == '/login') {
    if (req.body.rememberme) {
      req.session.cookie.maxAge = 1000 * 60 * 3;
    } else {
      req.session.cookie.expires = false;
    }
  }
  next();
});
app.use(passport.initialize());
app.use(passport.session());

req.body.rememberme 为真时我无法登录,而当req.body.rememberme 为假时用户被记住。 我也试过 connect-ensure-login 还是错了。

还有一个问题:我应该什么时候删除数据库中的 cookie 以及如何删除?

:)

其他代码与护照指南一模一样

路线:

app.get('/', passport.authenticate('local', {
  failureRedirect: '/login'
}), function(req, res) {
  res.redirect('/user/home');
});
app.post('/login', passport.authenticate('local', {
  failureRedirect: '/login'
}), function(req, res) {
  res.redirect('/user/home');
});

会话:

passport.serializeUser(function(user, done) {
  var CreateAccessToken = function() {
    var token = user.GenerateSalt();
    User.findOne({
      accessToken: token
    }, function(err, existingUser) {
      if (err)
        return done(err);
      if (existingUser) {
        CreateAccessToken();
      } else {
        user.set('accessToken', token);
        user.save(function(err) {
          if (err)
            return done(err);
          return done(null, user.get('accessToken'));
        })
      }
    });
  };
  if (user._id)
    CreateAccessToken();
});
passport.deserializeUser(function(token, done) {
  User.findOne({
    accessToken: token
  }, function(err, user) {
    if (err)
      return done(err);
    return done(err, user);
  });
});

和策略:

passport.use(new LocalStrategy(function(userId, password, done) {
  User.findOne().or([{
    username: userId
  }, {
    email: userId
  }]).exec(function(err, user) {
    if (err)
      return done(err);
    if (!user) {
      return done(null, false, {
        message: 'Invalid password or username'
      });
    }
    if (user.Authenticate(password)) {
      return done(null, user);
    } else {
      return done(null, false, {
        message: 'Invalid password or username'
      });
    }
  });
}));

我注意到 Express 只会在哈希值更改时更新 cookie。所以我修改了中间件中的代码

app.use(function(req, res, next) {
  if (req.method == 'POST' && req.url == '/login') {
    if (req.body.rememberme) {
      req.session.cookie.maxAge = 1000 * 60 * 3;
      req.session._garbage = Date();
      req.session.touch();
    } else {
      req.session.cookie.expires = false;
    }
  }
  next();
});

现在我可以使用“记住我”登录,但它仅适用于 Ubuntu 上的 chromium 和 firefox。我仍然无法在 Win7 和 Android 上使用 chrome 和 firefox 上的“记住我”复选框登录。

我在win7上的chrome上POST到“/login”时检查了响应标头,它具有与Ubuntu上相同的“Set-Cookie”字段,为什么它不能工作?


时间不同步...所以我发布了一个额外的时间字段。

$('#login').ajaxForm({
  beforeSubmit: function(arr, $form, option) {
    arr.push({
      name: '__time',
      value: (new Date()).toGMTString()
    });
  }
});

和“RememberMe”中间件:

app.use(function(req, res, next) {
  if (req.method == 'POST' && req.url == '/login') {
    if (req.body.rememberme) {
      req.session.cookie.maxAge = moment(req.body.__time).add('m', 3) - moment();
      req.session._garbage = Date();
      req.session.touch();
    } else {
      req.session.cookie.expires = false;
    }
  }
  next();
});

【问题讨论】:

  • 这在语义上是不是错误的?如果rememberme == true 表示cookie 不应该过期?您应该发布更多代码,而不是这三个中间件
  • 如果rememberme == true cookie 过期(在这种情况下为 3 分钟),否则 cookie 将成为会话 cookie(在浏览器会话完成时过期)。但我同意:需要更多代码。
  • 这段代码很混乱。您应该将关注点分开。 serializedeserialize 函数仅用于通过其 id 获取用户(使用数据库 id)并序列化为会话 cookie(如果您担心,id 不会以明文形式出现)。不要混入一些可疑的安全代码
  • @pfried 我不太清楚本地护照的工作原理,就像他们的指南一样,我在serialize 中制作了一个唯一令牌,并发现用户在deserialize 中获得了令牌,但我不清楚何时这些函数将被调用
  • 我最近也在做这个,这对我有点帮助:Node.js + express.js + passport.js : stay authenticated between server restart

标签: node.js express passport.js


【解决方案1】:

我遇到了和你一样的问题。以下代码适用于我:

app.post("/login", passport.authenticate('local',
    { failureRedirect: '/login',
      failureFlash: true }), function(req, res) {
        if (req.body.remember) {
          req.session.cookie.maxAge = 30 * 24 * 60 * 60 * 1000; // Cookie expires after 30 days
        } else {
          req.session.cookie.expires = false; // Cookie expires at end of session
        }
      res.redirect('/');
});

【讨论】:

  • 我已将示例时间从 3 分钟(比大多数会话短)修改为 30 天。我在想 3 分钟是不记得我的模式,...expires = false; 意味着永不过期。
  • @rjmunro 你为什么重定向到'/'?是根路径还是'login/'
  • 这不是我的代码 - 我只是添加了一些 cmets,但看起来它会在您登录后重定向到站点的根目录。这个答案是不久前写的 :-)。跨度>
【解决方案2】:

现在有一个 Passport 策略来添加由 Jared Hanson 编写的“记住我”功能。

https://github.com/jaredhanson/passport-remember-me

这通过在每个会话开始时发出一个唯一的记住我令牌来工作(使其失效以供将来使用)。因此,这可能是一个更安全的解决方案。

【讨论】:

  • 如果您的应用是 koa.js 应用,github.com/clthck/passport-remember-me 对我来说效果很好。它实际上是 jaredhanson 原始 repo 的一个分支,它只是添加了对 koa.js 应用程序的支持(以及koa-passport
  • 还值得注意的是,对于真正的“记住我”——您需要在缓存或数据库中对令牌进行某种长期持久性——否则服务器将将它们存储在内存中。您希望能够重新启动服务器并让记住我的令牌仍然有效
【解决方案3】:

确保app.use(express.bodyParser()) 位于您的中间件之上,因为您依赖于req.body.rememberme

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多