如何正确使用 Passport.js?
Posted
技术标签:
【中文标题】如何正确使用 Passport.js?【英文标题】:How to properly use Passport.js? 【发布时间】:2014-08-18 19:28:04 【问题描述】:我正在使用:
Node.js Express 4.0 Passport.js 用于身份验证的 Google OAuth 2对于每个用户,我将他的 Google 个人资料(电子邮件等)中的一些信息、访问和刷新令牌以及其他信息存储在 mysql 数据库中(我无法选择这项技术)用户在我的应用上注册时提供。
我看到了 passport.js 的不同用途,特别是关于该信息如何存储在会话中。
passport.js's configure page,我真的不知道 理解以下代码块的要点:
passport.deserializeUser(function(id, done)
User.findById(id, function(err, user)
done(err, user);
);
);
基本上,每次用户发出请求或访问页面时,都会向数据库发出请求并检索信息。有什么意义?它会大大降低应用程序的速度。调用serializeUser
时(即信息存储在会话中时)不应该从数据库中检索信息吗?
我了解到在 session
中存储 太多 信息会减慢
应用程序。什么是“太多”?它会使应用程序变慢多少?做
有人知道某处是否有测试吗?我的应用页面需要
关于我的用户的不同数据集(例如,主页将
只需要他的名字,而个人资料页面将需要一切,
另一个页面需要知道他拥有什么汽车等...)。我是不是该
当passport.authenticate
检查时,将所有这些信息存储在session
如果用户存在于数据库中(从而限制对数据库的读取请求
到大约一个),或者只在会话中存储他的 id 并拥有我的
页面在必要时向数据库发出额外请求?
我遇到的另一个问题:在注册过程中,我首先让用户登录他的
Google 帐户,我将他的个人资料的详细信息存储在某处,让他
填写额外信息的表格,然后我将所有内容插入
数据库。问题是我不知道如何正确存储他的谷歌
帐户详细信息,直到它们被插入数据库。暂时,
我将它们存储在session
,然后在插入时将其删除
是成功的。更具体地说,当在
我的数据库,我这样做,在我的passport.authenticate
回调中:
return done(null,false,userInfo);
因此,用户未通过身份验证,我有 2 个问题:我必须
将 userInfo
存储在某处,直到用户注册并且我有
注册完成后使用req.login()
“手动”记录他。
我是否应该允许他在他登录后立即进行身份验证? 谷歌帐户?如果他不会对我造成安全问题 没有完成注册?
最后,我阅读了有关使用 Reddis 的信息。这对我有帮助吗 这些问题?非常感谢!
【问题讨论】:
【参考方案1】:1) serializeUser 正在过滤数据并将其存储在会话 cookie 中。如果可以的话,通常在 cookie 中存储较少。无论如何,您都将调用 db 以获取有关用户的数据,因此您可以只存储用于检索和重建用户的 ID,如 deserializeUser 中所示。
来自 cookie 的请求由客户端提供给服务器,服务器将 cookie 反序列化为数据,解密 cookie 内容或从数据库中检索用户数据。然后响应发出,服务器序列化客户端数据,刮掉你不会存储在 cookie 中的东西并将它们放在 db 中,只在 cookie 中留下一个 id。
如果您正在进行加密,那么当您想通过运行多台机器来扩展时很容易搞砸,而每台机器都需要能够解密数据(不是很困难,但不必要的复杂性)
只在 cookie 中存放未加密的数据并不是最好的,此外 cookie 中的任何内容都可以为用户增加额外带宽使用的暗示。
2) 数据库调用应该非常快,否则无论如何您都会在其他地方体验到痛苦的用户体验。换句话说,我的强烈观点是,远离 cookie 的论据是压倒性的。
考虑到每个请求都会发送 cookie;它会更聪明,而不是将数据推入会话并增加开销,而是在用户发出请求后临时加载(缓存)用户数据一段时间,然后既没有数据库调用也没有来自 cookie 的开销当用户活跃在您的网站上时。
老实说,一开始你应该没问题,不用缓存。专注于让您的应用程序以最小的复杂性启动。这样您可以更快地根据用户反馈进行修改,并且错误更少。
3)当我玩护照时,我遇到了类似的问题。我会让护照完成它的工作并向用户授予护照级别验证(是的,他们已登录),然后单独进行更多数据收集。如果您担心安全问题,请将此护照级别的验证设置为未完全登录,并在升级到完全登录之前需要更多数据。
我可能对这个很不满意,但这是我的建议。
4) Redis 适用于您有多个节点实例并希望在内存中存储某些内容(例如计数器或缓存的用户数据)的情况。这样,节点代码中的变量就不会保存有关用户的缓存数据,当用户返回并且负载均衡器将它们拍摄到不同的实例时,另一个节点实例无法利用这些变量。 http://www.ourdailycodes.com/2013/09/redis-when-should-i-use-it.html
编辑: 我应该添加该会话使用 cookie,但只为用户提供服务器理解的唯一令牌,以便服务器可以在收到带有随附会话令牌的连接时重新收集用户的会话数据。我的理解是,这通常是 Session 工作的正确方式......但它因实现而异(如果我在这里错了,有人纠正我)。
【讨论】:
非常感谢您的精心推荐!我会尽量让我的应用程序简单(因为我还在学习 Node/Express/Passport),看看是否有用户抱怨性能不佳。 我希望有人能给出关于 cookie 与 db 基准测试的#2 的准确答案,以及关于 OAuth 的适当安全性的#3。 我还听说 OAuth 1 对于开发人员入门来说是一个更安全的选择:hueniverse.com/2012/07/26/oauth-2-0-and-the-road-to-hell 是的,我在开始玩 OAuth 2 时就读过这篇文章。我会在家里仔细阅读它,但是,它是从 2012 年开始的,所以我希望后面的人OAuth2 已经考虑了他的评论/建议等等,谷歌(我认为)正在使用 OAuth2 并计划放弃对 OAuth 1 的支持。但感谢您的链接:) 我的荣幸。如果有人提到这个话题,here's Google migration timetable。据他们说,OAuth 1.0 自 2013 年 10 月起已被弃用。【参考方案2】:我使用了 node.js 这是文档中的代码:
passport.serializeUser(function(user, done)
done(null, user.id);
);
passport.deserializeUser(function(id, done)
User.findById(id, function (err, user)
done(err, user);
);
);
这是代码,我修改以更好地理解:
var passport = require ('passport')
passport.serializeUser (function(user, done)
done(null, user.id);
);
passport.deserializeUser(function(id, done)
var user = _.find(fixtures.users, 'id', id)
if (user)
done (null, user);
else
done (null, false)
);
module.exports = passport;
在 serializeUser 中,客户端发送带有 'id' 的 cookie。这里 serializeUser 中的 '(user)' 参数是用户配置文件,客户端仅使用用户配置文件中的 'id' 向服务器发送请求。完成回调将 user.id 传递给服务器。
在 deserializedUser 中,服务器将查看数据库并从 serializedUser 中找到具有该 'id' 的用户并返回用户配置文件。 我使用“lodash”来使用查找和删除方法。
var _ = require ('lodash')
var user = _.find(fixtures.users, 'id', id)
find 将查找用户 id 并返回具有该 id 的用户配置文件。更多关于 lodash 的细节在这里:lodash。 之后,我正在检查用户是否存在然后返回用户,否则返回 false。
最后,我正在导出护照。
module.exports = passport;
【讨论】:
以上是关于如何正确使用 Passport.js?的主要内容,如果未能解决你的问题,请参考以下文章
Passport.js 使用 failureRedirect 呈现错误 401
如何在 passport-facebook / Passport.js 中捕获 FacebookAuthorizationError?