node.js - 将多个第三方和本地帐户与 Passport 链接在一起

标签 node.js authentication express authorization passport.js

我已按照建议成功将帐户链接到用户 here 。如果登录用户使用 OAuth 2.0 授权第三方(例如 Google Contacts API),我可以将该信息保存在帐户中,然后将该帐户与登录用户关联。

我想更进一步,以尽可能提供无缝的登录体验。一旦用户将其身份绑定(bind)到第三方帐户,我希望他们不仅能够使用本地策略(用户名/密码)登录,然后提取相关的第三方信息,而且还能够使用其他方式:注销时,连接到 Google 会将他们作为我的应用程序的用户登录,使 req.user = 他们的 User 信息,就像他们使用本地策略登录时一样。这是相关的代码块(显示的还有更多内容,但重点就在那里。

passport.use(new GoogleStrategy({
        clientID: google_params.client_id,
        clientSecret: google_params.client_secret,
        callbackURL: google_params.callbackURL,
        passReqToCallback: true
    },
    function(req, token, refreshToken, profile, done) {

...
        // If no user in session, set the req.user to the associated user
        User.findOne({
        'username': account.userId
        }, function(err, user) {
            console.log('Account exists already in DB, and is already tied to a user. Logging into users account.');
            req.user = user;
            return done(null, account);
        });

etc...

在检查序列化/反序列化函数时,此代码永远不会将用户或帐户信息序列化到 session ,因此虽然该信息确实在验证回调结束时传递,但它会在页面刷新时消失(同样,因为没有任何内容被保存到 session 中)。我该怎么办?我的想法正确吗?

最佳答案

答案有点晚了,但我一直在研究我正在构建的应用程序,它可能对其他人有帮助。

所以答案是,是的,您可以让用户链接他们的帐户,而不要求他们创建本地帐户(如 Scotch.io 教程中建议的那样)。诀窍是管理帐户的重复数据删除。

无论他们通过哪个提供商登录,我们都会按顺序处理以下检查:

  1. 如果该提供商已存在用户:请重新登录。
  2. 如果该提供商不存在用户:检查该电子邮件地址(或提供商之间的其他公共(public)字段)是否存在用户。如果是这样,请链接帐户并登录。
  3. 如果该提供商或其他提供商还没有用户:使用从提供商提取的信息创建新的用户模型,然后将其登录。

应对您支持的所有提供商执行此操作。通过使用由第三方服务预先验证的通用字段(例如电子邮件地址),我们可以消除重复帐户。另一个功能可能是允许用户手动将它们链接在一起,以应对他们想要链接具有不同电子邮件地址的帐户的情况(这种情况在 github 上经常发生,他们使用自己的个人帐户,然后想要将其连接到工作帐户,以 CI 提供商为例)

希望这有帮助。如果您找到替代解决方案,最好将其添加到此处或者遇到任何问题。我认为这是一个很常见的案例,可以将其变成一个 wiki。

** 更新 **

If you want to "link" accounts from multiple providers together, at that point you'll want a database with user records specific to your app, which in turn are associated with third-party account records. Then, in the verify callback, you'll want to perform whatever queries are necessary and supply your app-specific user record to done. That will keep things consistent, so that if someone had linked both Facebook and Twitter, they can return to the app and sign in with either one.

Further discussion about that topic is here: http://passportjs.org/guide/authorize.html

If you go that route (as I do in my apps), I use middleware like this to combine authentication and authorization into a single route:

function authnOrAuthzFacebook(req, res, next) {
  if (!req.isAuthenticated()) {
    passport.authenticate('facebook', { successRedirect: '/settings/accounts',
                                        failureRedirect: '/login' })(req, res, next);
  } else {
    passport.authorize('facebook-authz')(req, res, next);
  }
}

app.get('/facebook-login', authnOrAuthzFacebook);

此评论的应用示例can be seen here on GitHub (最终版本)。

因此,有一些替代版本可以完成相同的工作(取决于您想要如何处理它)。

关于node.js - 将多个第三方和本地帐户与 Passport 链接在一起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19970294/

相关文章:

http - AcceptSecurityContext 随机 SEC_E_LOGON_DENIED

mysql - Node.js 在 MySQL 查询上崩溃

javascript - 使用 HIGHCHARTS (xAxis dateTime) 添加点

node.js - Node : What's the most efficient way to read the last X bytes of a very large file (+1GB)?

authentication - SPA (Aurelia) + ASP.NET Core Web API + Google 身份验证

windows - 任何让我重新登录 "locked"Windows 7 的 Windows API?

javascript - 用 express 发回 CSV

javascript - 将 Socket.io 与 Node.js、Express 和 Jade 结合使用

javascript - 预期为 '===' 而看到的是 '==' eqeqeq

处理 Node.js TLS 服务器和 C TLS 客户端 (openSSL) 连接的正确方法