【问题标题】:Why is passport.serializeUser executed on each request?为什么对每个请求都执行 passport.serializeUser?
【发布时间】:2014-09-13 07:44:59
【问题描述】:

我正在使用 passport.js + passport-facebook-token 来保护我使用 Strongloop 的 Loopback Framework 构建的 API。

为什么passport反序列化成功后又要对反序列化的用户进行序列化?每个请求都会调用 passport.authenticate 方法!我做错了什么?

这是节点的日志:

deserializeUser, id: XXXXXXXXXXXXXXXX
User found.
serializeUser, id: XXXXXXXXXXXXXXXX
GET /api/events?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 304 182ms

这里是js代码:

passport.use(new FacebookTokenStrategy({
    clientID: XXXXXXXXXXXXXXXX,
    clientSecret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  },
  function(accessToken, refreshToken, profile, done) {
    //check user table for anyone with a facebook ID of profile.id
    User.findOne({
      'facebookId': profile.id
    }, function(err, user) {
      if (err) {
        return done(err);
      }
      if (user) {
        console.log("User found.");
        return done(err, user);
      } else {
        console.log("User not found.");
        User.create({
          email: profile.emails[0].value,
          facebookId: profile.id,
          password: 'secret'
        }, function(err, user) {
          console.log(user.id);
          console.log(user.email);
          console.log(user.facebookId);
          console.log("User created");
          return done(err, user);
        });
      }
    });
  }));

passport.serializeUser(function(user, done) {
  console.log('serializeUser, id: ' + user.facebookId);
  done(null, user.facebookId);
});

passport.deserializeUser(function(id, done) {
  console.log('deserializeUser, id: ' + id);
  User.findOne({
    'facebookId': id
  }, function(err, user) {
    if (!err) {
      done(null, user);
    } else {
      done(err, user);
    }
  });
});

【问题讨论】:

  • 能否展示定义中间件处理身份验证的代码?它应该类似于passport.authenticate("facebook", function ....)。如果您执行app.get("/*", passport.authenticate()) 之类的操作,它会按预期工作。
  • 这是为此添加的唯一 loc:app.use(passport.authenticate('facebook-token'));
  • 嗯,好的,我明白了。但我的理解是它应该作为中间件添加,因为它可以保护我的 api 免受未经授权的访问......在哪里添加这条线的正确位置?或者你有什么建议?

标签: javascript node.js passport.js passport-facebook


【解决方案1】:

关于您关于为什么在每个请求上调用passport.authenticate 的问题,这是因为您可能在任何路由逻辑发生之前将其定义为中间件。

如果你的应用有私有公共部分,你可以这样做:

// Define a specific that will handle authentication logic
app.get("/auth", passport.authenticate('facebook-token',function(){...});

// Public sections which do not require authentication
app.get("/public1",...);
app.post("/public2",...);

// Private sections which do require authentication
app.get("/private1", function(req,res,next){
   if (req.isAuthenticated()){ // Check if user is authenticated
       // do things...
   }else{ // Wow, this guy is not authenticated. Kick him out of here !
       res.redirect("/auth");
   }
});

现在,如果您有多个私人部分,您可能会发现为每个私人部分做同样的事情有点繁琐。 您可以定义一个自定义函数来检查用户是否已通过身份验证,如果是,则允许请求继续进行。 类似的东西

function isThisGuyAuthenticated(req,res,next){
   if (req.isAuthenticated()){
      return next(); // Ok this guy is clean, please go on !
   }else{
      res.redirect("/auth"); // This guy is shady, please authenticate !
   }
}

并像这样使用它:

app.get("/private1",isThisGuyAuthenticated, doCrazySecretStuff); // doCrazySecretStuff will not be called if the user is not authenticated
app.get("/private2", isThisGuyAuthenticated, getCocaColaRecipe);
app.get("/private3", isThisGuyAuthenticated, flyToMars);
app.get("/public", showInfo); // showInfo will be called whether the user is authenticated or not

现在,如果您的应用只有私有部分,您可以通过将 isThisGuyAuthenticated 定义为中间件来避免重复调用它(但不能将 passport.authenticate 本身定义为中间件!);

// Endpoint that will be hit is the user is redirected to /auth
// BEWARE it needs to be above the middleware, otherwise you'll end up with an infinite redirection loop
app.get("/auth", passport.authenticate('facebook-token',function(){...});

// Middleware that will be called on every request
app.use(isThisGuyAuthenticated);

// You app's endpoints
app.get("/private1", doCrazySecretStuff); // doCrazySecretStuff will not be called if the user is not authenticated
app.get("/private2", getCocaColaRecipe);
app.get("/private3", flyToMars);

清楚吗?

EDIT :我错误地将中间件放在“/auth”端点之前。确保它放置在

之后

【讨论】:

  • 很好的答案!非常感谢,我想现在已经很清楚了,让我试试,我会检查它作为答案!
  • 不客气。如果您有任何问题,请告诉我。请检查我的编辑,我最初犯了一个严重的错误。
  • 没错。我修正了 /auth 函数中的一个小错字......!但它有效。现在只有第一个对 /auth 的请求需要大约 200 毫秒的其他请求,它利用现有会话,并且速度非常快(
  • 我们可以谈谈吗,我对这个答案有些疑问?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多