【发布时间】: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 == truecookie 过期(在这种情况下为 3 分钟),否则 cookie 将成为会话 cookie(在浏览器会话完成时过期)。但我同意:需要更多代码。 -
这段代码很混乱。您应该将关注点分开。
serialize和deserialize函数仅用于通过其 id 获取用户(使用数据库 id)并序列化为会话 cookie(如果您担心,id 不会以明文形式出现)。不要混入一些可疑的安全代码 -
@pfried 我不太清楚本地护照的工作原理,就像他们的指南一样,我在
serialize中制作了一个唯一令牌,并发现用户在deserialize中获得了令牌,但我不清楚何时这些函数将被调用
标签: node.js express passport.js