我正在使用带有express的passportJS来通过本地策略验证用户身份。我看过几篇关于如何设置护照和执行流程的文章。虽然关于护照的大部分内容都可以通过搜索找出来,但是用户的序列化和反序列化使我感到困惑。
据我所知,它用于在会话中保存用户信息以进行持久登录。我的序列化和反序列化代码是
passport.serializeUser(function(user, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done){
User.findById(id, function(err, user){
done(err, user);
});
});
关于这个的问题
1)谁调用并填充serializeUser和deserializeUser的参数?它如何访问用户对象?为了理解这一点,我添加了像
这样的日志 passport.serializeUser(function(user, done){
console.log(arguments.callee.caller);
done(null, user.id);
});
输出中有 [功能:传递] 谁能解释一下呢?
2)我正在使用mongodb来存储用户信息。 MongoDB将_id作为文档的默认ID。理想情况下,serializeUser和deserializeUser应该使用user._id而不是user.id.但它在user.id中工作正常,这在User用户中是不可用的。这是在控制台中打印的用户对象
{ _id: 5505f231b810dbd4098ac76a,
__v: 0,
google: {},
twitter: {},
facebook: {},
local:
{ password: '$2a$08$9NGd0xNu0JbWMZ07ufyFRu8guwy147k8IBl5cAC4Y8APOuxreNI32',
email: 'xxxx@xxx.com' } }
这怎么可能?
3)执行done
方法后控制流执行的位置是什么?
答案 0 :(得分:19)
经过长时间的搜索,我发现了article ,它非常清楚地解释了身份验证流程。
- 当用户提交登录表单时,对/ login的POST请求为 导致执行 passport.authenticate 我们已经建立了中间件。
- 由于该路由的身份验证中间件已配置为 处理当地战略,护照将援引我们 实施当地战略。
- Passport接受req.body.username和req.body.password和 将其传递给我们在本地策略中的验证功能。
- 现在我们做的事情:从数据库加载用户并检查 如果给出的密码与数据库中的密码匹配。
- 如果一切顺利,我们希望用户登录,我们调用done(null,user)。
- 调用完成将使流程跳回 的 passport.authenticate 即可。它传递了错误,用户和其他 info对象(如果已定义)。
- 如果用户通过,中间件将调用req.login(a 请求附带的护照功能)。
- 这将调用我们定义的 passport.serializeUser 方法 早。
醇>
- Express加载会话数据并将其附加到req。由于护照将序列化用户存储在会话中
- passport.session 中间件是一种将加载的Passport策略 如果找到序列化的用户对象,则将用户对象放到req.user上 在服务器中。
在请求上调用- passport.initialize ,它会找到附加到会话的passport.user。接下来, passport.session 是 调用。
- passport.session中间件调用 passport.deserializeUser 建立。将加载的用户对象作为req.user附加到请求。
醇>
我希望它有所帮助。
答案 1 :(得分:1)
由于您使用的是PassportJS,所以我认为您必须对它的工作原理有所了解。所以我会添加进一步的信息,我认为这将清除你的怀疑。
Passport配置涉及三个部分:
你的问题的答案在于第3部分,会议。
如果验证成功,将通过用户浏览器中设置的cookie建立和维护会话。每个后续请求都不包含凭据,而是包含标识会话的唯一cookie。为了支持登录会话,Passport会将 user
实例序列化和反序列化到会话中。
根据您的实现,只有用户ID被序列化到会话中,保持会话中存储的数据量很小。收到后续请求时,此ID用于查找用户,该用户将恢复为 req.user
在护照中,我们可以选择编写自己的序列化和反序列化逻辑,以便我们可以选择任何适当的数据库,而不是严格的规则。
总而言之,在成功验证后,用户对象被序列化并存储在会话中,如果您调用 req.user ,那么您将能够检索相同的用户对象。
答案 2 :(得分:0)
您正在使用基于cookie的身份验证。为了为您(也许是一个在所有方面都非常新的人)回答这个问题,我将尝试非常详细。所以这是一个场景...
让我们想象一下,该用户以前已经登录了我们的应用程序,因此,在Users集合中有一条记录与此配置文件匹配,因此服务器说:“看起来您具有与user123相同的google配置文件ID(已保存在我们的数据库中。我需要给您一些标识性令牌,说您毫无疑问:'user123',并且该令牌将在对我们服务器提出的任何后续请求中标识您”
到那时,为了生成少量令牌或少量标识信息,我们将定义一个名为“ serializeUser”的函数。护照将通过我们在最后一步中获取的用户模型自动被护照调用。因此,为解释起见,我们将使用该用户模型来生成我们的识别用户信息,然后,将识别信息传递回护照,以便护照可以自动将少量令牌填充到护照中。用户的Cookie。
现在,一旦用户决定要发出某种类型的跟进请求,例如从浏览器回到我们服务器的帖子列表或邮件列表或其他内容,则该请求的Cookie将是由浏览器自动添加到请求中,护照将从cookie中获取该标识信息,然后将其传递到名为“ deserializeUser”的第二个函数中,在该函数中,我们将获取该标识令牌并将其转换回唯一标识此用户的用户模型。
总结...
在第一个过程(seralizeUser)中,“用户”是一个用户模型实例(如果使用猫鼬,则是猫鼬模型)...我们要做的就是将那个模型转换为id。
在第二个过程(deserializeUser)中,我们做的恰好相反,将id转换为猫鼬模型实例。为此,我们必须使用我们的数据库中存在的所有不同用户搜索或查询我们的big'ol集合(使用findById),在找到该特定用户之后,我们将在该用户上调用“完成”用户,这意味着我们将退还该用户。