【问题标题】:How to passing data in TwitterStrategy, PassportJS?如何在 Twitter Strategy、Passport JS 中传递数据?
【发布时间】:2013-08-22 07:09:23
【问题描述】:

我有三种用户:

  1. 查看者(登录链接:auth/v/twitter)
  2. 创作者(登录链接:auth/c/twitter)
  3. 管理员(登录链接:auth/a/twitter)

而且我还有 3 个不同的数据库/集合

  1. c_viewer
  2. c_creator
  3. c_admin

每种用户都有不同的登录链接。

现在我们来看看代码

var passport = require('passport')
   ,TwitterStrategy = require('passport-twitter').Strategy;

passport.use(new TwitterStrategy({
  consumerKey: config.development.tw.consumerKey,
  consumerSecret: config.development.tw.consumerSecret,
  callbackURL: config.development.tw.callbackURL
},

function(token, tokenSecret, profile, done) {
  process.nextTick(function(req, res) {
    var query = User.findOne({ 'twId': profile.id});
    query.exec(function(err, oldUser){
      if(oldUser) {
        done(null, oldUser);
      } else {
        var newUser = new User();
        newUser.twId = profile.id;
        newUser.twUsername = profile.username;
        newUser.name = profile.displayName;
        newUser.avatar = profile.photos[0].value;
     -> newUser.age = req.body.creator.age; ???
        newUser.save(function(err) {
          if(err) throw err;
          done(null, newUser);
        });
      };
    });
  });
}));

app.get('/auth/c/twitter', passport.authenticate('twitter'),
function(req, res) {
  var userUrl = req.url;
  // codes to pass the userUrl to TwitterStrategy
});
app.get('/auth/twitter/callback', 
passportForCreator.authenticate('twitter', { successRedirect: '/dashboard', failureRedirect: '/' }));

这是我的表格

<input type="text" name="creator[age]" placeholder="How old are you?">
<a id="si" class="btn" href="/auth/c/twitter">Sign in</a>

我的问题:

1. 我们可以将&lt;input&gt; 数据传递给登录进程吗?所以我们可以读取 TwitterStrategy 中的输入数据,并保存到数据库
2. 我们可以从登录 url 中获取“c”吗(auth/ c /twitter)并将其传递给 TwitterStrategy?所以我们可以简单地签入不同的数据库/集合并更改查询。

【问题讨论】:

    标签: node.js authentication express passport.js


    【解决方案1】:

    这个想法是在将用户重定向到 twitter 进行身份验证之前存储您的值,并在用户返回后重新使用这些值。

    OAuth2 包含范围参数,非常适合这种情况。不幸的是,TwitterStrategy 基于 OAuth1。但我们可以解决它!

    下一个技巧是关于创建用户的。 声明策略时不应该这样做(因为您无法访问输入数据),但稍后,在最后一次身份验证回调中 see here the callback arguments.

    宣布您的策略:

    passport.use(new TwitterStrategy({
      consumerKey: config.development.tw.consumerKey,
      consumerSecret: config.development.tw.consumerSecret,
      callbackURL: config.development.tw.callbackURL
    }, function(token, tokenSecret, profile, done) {
      // send profile for further db access
      done(null, profile);
    }));
    

    在声明您的身份验证 URL 时(重复 a/twitter 和 v/twitter):

    // declare states where it's accessible inside the clusre functions
    var states={};
    
    app.get("/auth/c/twitter", function (req, res, next) {
      // save here your values: database and input
      var reqId = "req"+_.uniqueId();
      states[reqId] = {
        database: 'c',
        age: $('input[name="creator[age]"]').val()
      };
      // creates an unic id for this authentication and stores it.
      req.session.state = reqId;
      // in Oauth2, its more like : args.scope = reqId, and args as authenticate() second params
      passport.authenticate('twitter')(req, res, next)
    }, function() {});
    

    那么在声明回调的时候:

    app.get("/auth/twitter/callback", function (req, res, next) {
      var reqId = req.session.state;
      // reuse your previously saved state
      var state = states[reqId]
    
      passport.authenticate('twitter', function(err, token) {
        var end = function(err) {
          // remove session created during authentication
          req.session.destroy()
          // authentication failed: you should redirect to the proper error page
          if (err) {
            return res.redirect("/");
          }
          // and eventually redirect to success url
          res.redirect("/dashboard");
        }
    
        if (err) {
          return end(err);
        }
    
        // now you can write into database:
        var query = User.findOne({ 'twId': profile.id});
        query.exec(function(err, oldUser){
          if(oldUser) {
            return end()
          } 
          // here, choose the right database depending on state
          var newUser = new User();
          newUser.twId = profile.id;
          newUser.twUsername = profile.username;
          newUser.name = profile.displayName;
          newUser.avatar = profile.photos[0].value;
          // reuse the state variable
          newUser.age = state.age
          newUser.save(end);
        });
      })(req, res, next)
    });
    

    【讨论】:

    • 这是一个不错的技巧,我已经按照你的代码,但是有一个错误说“无法读取未定义的属性'状态'”而且对于这个年龄,我没有得到任何价值。我使用 cheerio 包有什么建议吗? @Feugy
    • 对不起:我忘了声明 states 变量(代码现在已编辑)。对于输入检索,cheerio 的工作方式与 jQuery 完全一样:它提供了一个 val() 方法来获取输入内容。也许您检索它太早,或者也许选择器不好。您应该发布您的 html +js 代码。
    • 是的,我添加了var states = {},但仍然出现同样的错误。这是我的 app.js 和 index.ejs 文件。 jsfiddle.net/3n65z
    • 嗨@Feugy,我仍然坚持这种情况。好像登录后我无法访问 req.session。
    • 好技巧,但是如果您使用的是无会话 API(就像您不在 API 实例之间共享会话)...这有点问题:/
    猜你喜欢
    • 1970-01-01
    • 2019-04-13
    • 2017-01-02
    • 2014-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多