Express.js/Passport 应用程序为每个请求创建新会话,尽管请求标头中有会话 ID

Posted

技术标签:

【中文标题】Express.js/Passport 应用程序为每个请求创建新会话,尽管请求标头中有会话 ID【英文标题】:Express.js/Passport app creating new session for each request, despite session ID in request headers 【发布时间】:2013-07-26 04:45:13 【问题描述】:

这在以前没有被注意到,因为对于客户端-服务器通信,不需要通过 XHR 进行身份验证(到目前为止)。在实现一些集成测试时,我正在向应用程序的真实实例创建真正的请求 node-xmlhttprequest。用户在第一个请求中进行身份验证,理论上用户的唯一标识符和其他一些相关信息存储在会话中(正如我所说,这对于不需要通过 XHR 确认身份的真实客户来说很好用)。出于某种原因,即使使用完全相同的会话 ID 触发后续请求,我也无法在后续请求中检索会话,因此无法看到用户已通过身份验证,这会导致测试失败,其中没有发生预期的行为,并且 HTTP 401 UNAUTHORIZED 正在填满终端。

我见过几个看起来像这样的问题,但其中似乎不存在“相同会话 ID”的问题。

我是否需要手动将 Set-Cookie 标头添加到所有 XHR 请求?太可怕了,一定有更好的办法!

所以人们喜欢源代码,这里有一些来自测试,触发这些请求:

// Ensure logged in before sending request, to verify that authorized
// users encounter the expected behaviour.
jQuery.post(domain+'/login', email:'test@express.app', password:'12345678',
function(data,x,y)
  data.should.equal("true")
  jQuery.ajax(url:domain+'/event', type:"POST",
    name: "TestEvent", location: "TestVille",
    startDate: new Date('2013-09-01'), startTime: '6:45 pm',
    description: "Test Event #1", success: state.success,
    error: state.error, completed: state.completed
  )
)

登录发生,用户 ID 被写入会话(`req.logIn() 应该这样做,并且它不报告任何失败),用户 ID 的序列化不报告任何失败,我非常困惑为什么使用相同会话 ID 的后续请求无法找到序列化的用户 ID。

我一般不参与网络开发,所以这对某些人来说可能很明显,但我整天都在寻找答案,但根本找不到答案。我将不胜感激,并很乐意提供尽可能多的代码来说明问题所在。

一些可能相关的附加代码点:

用户ID的序列化/反序列化(目前以最简单的方式实现 方式——这是在初始化护照和 passpot.session() 之后的中间件初始化的早期阶段。这对于非 XHR 请求非常有效)

// Serialize user for passport session-store
// Currently only serializing 'user_id'
passport.serializeUser(function(user, done) 
  done(null, user._id)
)

// Deserialize user from session-store to provide
// access to the User instance
passport.deserializeUser(function(id, done) 
  User.findById(id, function(err, user) 
    done(err, user)
  )
)

通过本地策略认证用户:

passport.use(new LocalStrategy(
    usernameField: "email", passwordField: "password",
    passReqToCallback: true, failureFlash: true
  ,
  function(req, email, password, done) 
    User.findByEmail(email, function(err, user) 
      if(user) 
        if(err) console.log(err)
        if(user instanceof UserLocal) 
          user.verifyPassword(password, function(err, match) 
            if(err) console.log(err)
            if(!match) 
              return done(err, false,
                "Username or password is incorrect.")
            
            return done(null, user)
          )
         else 
        var msg = "Account registered under " + user.providerName()
                + ", please login using " + user.providerName()
        return done(err, false, msg)
      
     else 
      return done(err, false, "Username or password is incorrect.")
    
  )
)

最后是首先写入会话的请求:

function loginHelper(req, res, next) 
  passport.authenticate('local', 
    failureFlash:true,
    failureRedirect: false,
    successRedirect: false 
  ,
  function(err, user, info) 
    req.logIn(user, function(err) 
      if(!err) err = 
      if(req.xhr) 
        console.log(req.session)
        res.status(200).end(err.message || "true")
       else 
        if(err.message) req.flash('error', err.message)
        else res.redirect('/')
      
    )
  )(req, res, next)

我知道有一些奇怪的事情,比如无论登录状态如何都发送 200 状态,但我可以确认序列化的用户 ID 在初始登录 XHR 请求中写入会话,并且在后续 XHR 中没有反序列化请求。

我相信我已经提到过,我在这方面相对缺乏经验,并且非常可以使用助推器。任何帮助将不胜感激,在此先感谢。

【问题讨论】:

你找到解决办法了吗 【参考方案1】:

这对我有帮助 首先

app.use(express.static(__dirname + '/public',  maxAge: oneDay ));

并更新函数以不触发数据库

 passport.serializeUser( (user, done) => 
        var sessionUser =  id: user.dataValues.id, fio: user.dataValues.fio, email: user.dataValues.localemail, role: user.dataValues.role, login: user.dataValues.login,  position: user.dataValues.position 
        done(null, sessionUser)
    )

    passport.deserializeUser( (sessionUser, done) => 
        // The sessionUser object is different from the user mongoose collection
        // it's actually req.session.passport.user and comes from the session collection
        done(null, sessionUser)
    )

https://www.airpair.com/express/posts/expressjs-and-passportjs-sessions-deep-dive

【讨论】:

以上是关于Express.js/Passport 应用程序为每个请求创建新会话,尽管请求标头中有会话 ID的主要内容,如果未能解决你的问题,请参考以下文章

如何在 express.js/passport-http-bearer 中撤销 express-jwt 令牌

phonegap ajax 用户身份验证与 nodejs-express-mongodb-passport js

使用 express js、passport s 保护 GraphQL 查询

Nodejs + Passport.js + Redis:如何在 Redis 中存储会话

如何在 passport-jwt 中获取 rawJWT 字符串?

使用 Angular、node.js 和身份提供者的 SAML 身份验证