NodeJS 不会存储会话数据,因此身份验证失败

8qgya5xd  于 2023-10-17  发布在  Node.js
关注(0)|答案(1)|浏览(128)

在我的express应用程序中,我在localhost:3000上进行了很好的注册和身份验证。登录后,我console.log'ged' req.session.userId,这给了我一个正确的ID。因此,我被授权发表新文章,但只要我点击新文章的链接,我就会被重定向回主页。我对会话和cookie有点困惑,我不确定哪一个在不同的路径之间持续存在,哪一个不存在。index.js:

const session = require('express-session')

app.use(session({
  secret: 'keyboard cat',
  saveUninitialized: true,
  cookie: { maxAge: 120000 },
  resave: false
}))

app.use("*", (req, res, next) => {
    loggedIn = req.session.userId;
    next()
});

app.use(flash());

app.get('/posts/new', authMiddleware, newPostController)

app.post('/posts/store', authMiddleware, storePostController)

app.post('/users/register', redirectIfAuthenticatedMiddleware, storeUserController)

app.get('/auth/login', redirectIfAuthenticatedMiddleware, loginController)

authMiddleware.js:

const User = require('../models/User')

module.exports = (req, res, next) => {
  User.findById(req.session.userId)
    .then((user) => {
      console.log(req.session.userId);
      if(!user ) { return res.redirect('/') }
      next()
    })
    .catch((error) => { 
      return res.redirect('/') })
}

loginUser.js:

const bcrypt = require('bcrypt')
const User = require('../models/User')

module.exports = (req, res) =>{
  const { username, password } = req.body;
  req.session.message = [];
  req.flash('data', req.body);
  console.log(req.body);
  User.findOne({ username: username })
    .then((user) => {
      if(user) {
        bcrypt.compare(password, user.password, (error, same) => {
          if(same) {
            req.session.userId = user._id
            res.redirect('/')
          }
          else {
            if(password === "") {
              req.session.message[1] = "Provide Password"
        }
            else { req.session.message[1] = "Password is incorrect" }
            req.flash('message', req.session.message);
            res.redirect('/auth/login')
          }
        })
      }
      else {
        if(username === "" && password === "") {
        req.session.message = ["Provide Username", "Provide Password"];
    }
    else if(username === "") {
      req.session.message[0] = ["Provide Username"]
    }
    else {
      req.session.message[0] = "Username is incorrect"
    }
        req.flash('message', req.session.message);
        res.redirect('/auth/login')
      }
    })
}

以下是app.cyclic.sh日志:

App listening on port 5000
 { username: 'Nacy', password: '1111' }
 Session {
  cookie: {
    path: '/',
    _expires: 2023-10-06T09:25:52.388Z,
    originalMaxAge: 120000,
    httpOnly: true
  },
  message: [],
  flash: { data: [ [Object] ] },
  userId: '650bde898e3d6b08b6b876e3'
}
 undefined
 Session {
  cookie: {
    path: '/',
    _expires: 2023-10-06T09:25:57.165Z,
    originalMaxAge: 120000,
    httpOnly: true
  }
}
 Listening ...

我想指出的是,在极少数情况下,req.session.userId确实会持续请求新的post get请求,但这种情况发生在三十次尝试中的一次。在这些罕见的情况下,我可以看到正确的id被打印到控制台。然后我填写新帖子的表格,点击提交按钮,这是帖子请求,但失败的概率为100%。在我试图保存一个帖子的20次中,没有一次被保存到Mongo Atlas。任何想法将不胜感激。

q0qdq0h2

q0qdq0h21#

您遇到的问题可能是由于在不同环境中处理会话和Cookie的方式。当您在本地运行应用时,浏览器和服务器位于同一台机器上,因此可以轻松共享Cookie和会话。但是,当您部署应用时,您的服务器和客户端位于不同的计算机上,由于安全限制,Cookie可能无法按预期共享。
这里有几个你可以检查的东西:
1.安全Cookie:如果您的生产环境使用HTTPS(它应该使用HTTPS),则需要将会话cookie的安全选项设置为true。这告诉浏览器只通过HTTPS发送cookie。

app.use(session({
  secret: 'keyboard cat',
  saveUninitialized: true,
  cookie: { 
    maxAge: 120000,
    secure: true, // Add this line
    httpOnly: true // And this line if it's not already there
  },
  resave: false
}))
  1. SameSite Cookies:某些浏览器要求为Cookie设置SameSite属性。此属性可以具有以下三个值之一:严格、宽松或无。如果设置为Strict,则仅当请求来自同一站点时才会发送Cookie。这是部署应用程序时常见的问题来源,因为您的服务器和客户端现在位于不同的站点上。
app.use(session({
         secret: 'keyboard cat',
         saveUninitialized: true,
         cookie: { 
             maxAge: 120000,
             secure: true,
             httpOnly: true,
             sameSite: 'none' // Add this line
                 },
             resave: false
          }))

1.域和路径:如果您的服务器和客户端位于不同的子域上,则可能需要设置cookie的域和路径选项。

app.use(session({
secret: 'keyboard cat',
saveUninitialized: true,
cookie: { 
   maxAge: 120000,
   secure: true,
   httpOnly: true,
   sameSite: 'none',
   domain: '.yourdomain.com', // Add this line
   path: '/' // And this line
        },
   resave: false
}))

请记住将. yourdomain.com替换为您的实际域名。
1.信任代理:如果你的应用运行在代理(如Nginx)之后,你需要告诉Express信任代理。

app.set('trust proxy', 1) // Add this line
 app.use(session({
 secret: 'keyboard cat',
 saveUninitialized: true,
 cookie: { 
 maxAge: 120000,
 secure: true,
 httpOnly: true,
 sameSite: 'none',
 domain: '.yourdomain.com',
 path: '/'
 },
  resave: false
 }))

请尝试这些建议,看看它们是否能解决您的问题。

相关问题