req.session无法存储数据

3
我正在尝试实现一个登录系统,用户可以在网站上注册,然后使用其帐户登录。一旦用户登录,他就可以编辑个人信息。
为了检查用户是否已登录,我尝试将req.session.isLoggedIn设置为true,然后检查该值是否为true以访问网站的某些区域。问题是,在我刚登录后,我打印了req.session的值,我看到了我刚刚设置的值,但之后,当我尝试在另一个路由中检查req.session.isLoggedIn的值时,我得不到任何值。
以下是我的代码:

const express = require('express');
const app = express();
var { Client } = require('pg');
var bcrypt = require('bcrypt');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var cors = require('cors');
var path = require('path');
var session = require('express-session');
var url = require("url");


app.use(cors());
app.use(express.static(path.join(__dirname, 'client/build')));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 600000000 }}))

const client = new Client({
  user: 'xxxxxxxxxxxxx',
  host: 'xxxxxxxxxxxxx',
  password: 'xxxxxxxxxxxxxxx',
  database: 'xxxxxxxxxxxxxx',
  port: 5432,
  ssl: true
})
client.connect();

/*Rutas*/

/*Seleccionar huellas pertenecientas a una cierta categoria*/
app.get('/api/huellas/:categoria', (req, res) => {
  client.query('SELECT * FROM huellas WHERE categoria = $1 AND activo = TRUE', [req.params.categoria], (err, query) => {
    if (err) {
      console.log(err.stack);
    } else {
      res.json(query.rows);
    }
  });
});

/*Listar todas las huellas*/
app.get('/api/mostrarHuellas', function(req, res, next) {
  client.query('SELECT * FROM huellas', (err, query) => {
    if (err) {
      console.log(err.stack);
    } else {
      res.json(query.rows);
    }
  });
});

app.get('/api/buscarHuellas/', function(req, res) {
  console.log(req);
  console.log("nombre: " + req.query.nombre + " categoria: " + req.query.categoria + " estado: " + req.query.estado);
  client.query('SELECT * FROM huellas WHERE (nombre = $1 AND categoria = $2 AND estado =  $3) AND activo = TRUE', [req.query.nombre, req.query.categoria, req.query.estado], (err, query) => {
    if (err) {
      console.log(err.stack);
    } else {
      res.json(query.rows);
    }
  });
});

app.post("/api/registro", function(req, res) {
  var email = req.body.email;
  var password = bcrypt.hashSync(req.body.password, 10);
  client.query('INSERT INTO usuarios(email, password, huella) VALUES ($1, $2, $3)', [email, password, req.body.huella], function(err, result) {
    if(err) {
      //console.log(err.stack);
      res.json(err);
    }
    else {
      console.log('row inserted');
      res.json("ok");
    }
  });
});

app.post("/api/login", function(req, res) {
  client.query('SELECT * FROM usuarios WHERE email = $1', [req.body.email], (err, query) => {
    if (err) {
      console.log(err.stack);
    } else {
      if(bcrypt.compareSync(req.body.password, query.rows[0].password)){
        req.session.isLoggedIn = true;

        console.log(req.session);
        res.json("ok");
      }
      else{
        res.json("clave invalida");
      }
      res.end();
    }
  });
});

app.get("/api/logout", function(req, res) {
  req.session.destroy();
});

app.get("/api/sessions", function(req, res){
  console.log(req.session);
  if(req.session.isLoggedIn) {
    console.log("logged in!");
  }
});


const port = process.env.PORT || 5000;
app.listen(port);

当我访问 /api/login/ 时,在终端中会收到如下输出,我可以看到 isLoggedIn:。

    Session {
  cookie: 
   { path: '/',
     _expires: 2017-09-05T00:29:19.786Z,
     originalMaxAge: 600000000,
     httpOnly: true },
  isLoggedIn: true }

但是在此之后,当我访问/api/sessions/时,输出如下:

Session {
  cookie: 
   { path: '/',
     _expires: 2017-09-05T00:29:21.451Z,
     originalMaxAge: 599999999,
     httpOnly: true } }

我正在使用Nodejs和Expressjs。另外,我正在服务于一些存储在/client/build中的静态文件,并且它们工作得很好。
提前致谢!
编辑:
这是我的登录处理方法代码,我正在使用react和react-router 4:

handleSubmit(event){
   event.preventDefault();
   fetch('/api/login', {
   method: 'post',
   headers: {'Content-Type':'application/json'},
   body: JSON.stringify({
     "email": document.getElementById("email").value,
     "password": document.getElementById("pwd").value
   })
   })
     .then(response => response.json())
     .then(res => {
        switch (res) {
          case "clave invalida":
            alert("clave invalida");
            break;
          case "ok":
            alert("sesion iniciada");
            this.props.history.push("/");
            break;
         default:
           alert("Error. Contacte a un administrador");
           break;
       }
     })
     .catch(err => console.log(err));
  };

2个回答

5

我刚刚找到了一个解决方案。我使用了@ytibrewala在这里发布的解决方案,以及@nlawson在这里发表的评论。我做了如下操作:

显然,默认情况下fetch方法不会发送cookie,因此您需要在AJAX调用中设置credentials参数,我是这样做的:

AJAX调用

  handleSubmit(event){
   event.preventDefault();
   fetch('http://localhost:5000/api/login', {
   method: 'post',
   credentials: 'include',
   headers: {'Content-Type':'application/json'},
   body: JSON.stringify({
     "email": document.getElementById("email").value,
     "password": document.getElementById("pwd").value
   })
   })
     .then(response => response.json())
     .then(res => {
       console.log(res);
       if(res.isLoggedIn){
         alert("Signed in");
         this.props.history.push("/hueprint");
       }
       else{
         alert("Invalid user or password");
       }
     })
     .catch(err => console.log(err));
  };

我使用了include,因为我不在同源。有关credentials参数接受的值的更多信息可以在此处查找

然后,在我的浏览器中遇到了CORS问题,所以我在后端的index.js文件上进行了更改:

index.js

app.use(cors({credentials: true, origin: true}));

现在,每次我在我的网站中使用handleSubmit方法,并且我检查打印req.session的测试路由,我看到我的isLoggedIn参数已经正确地设置了。

我留下了我的路由,供那些想要查看它的人:

app.post("/api/login", function(req, res) {
  client.query('SELECT * FROM usuarios WHERE email = $1', [req.body.email], (err, query) => {
    if (err) {
      console.log(err.stack);
    }
    else {
      if(bcrypt.compareSync(req.body.password, query.rows[0].password)){
        console.log("password matches");
        req.session.isLoggedIn = true;
        req.session.save();
        res.send(req.session);
      }
      else{
        console.log("password doesn't match");
        req.session.isLoggedIn = false;
        req.session.save();
        res.send(req.session);
      }
    }
  });
});


1
很好,哇,我也从你这里学到了新的东西,感谢你的出色回答!现在正在检查https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials这个页面,凭据必须为“true”,页面才能使用数据 :) 做得好。 - Ahmed Can Unbay
1
谢谢。我整天都在寻找这个答案。使用 credentials: 'include' 和将 {credentials: true, origin: true} 添加到 cors() 调用选项中解决了请求会话数据为 undefined 的问题。 - Chad Johnson

1

每当您想保存cookie时,都需要使用res对象发送它们。这是我的代码,它可以工作。看一下。

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


app.get("/", function(req, res){
  if(req.session.views){
    req.session.views++;
  }else{
    req.session.views = 1;
  }
  res.status(200).send(req.session);
})


app.get("/checkerPage", function(req, res){
  console.log(req.session); //it logs the correct data.
  res.send("whatever");
})

//post req

app.post("/post", function(req, res){
  req.session.user = "myname";
  res.send(req.session);
  console.log(req.session);
});

我的索引 HTML

<form action="/post" method="post">
  <input type="text" name="myName" value="">
  <input type="submit" name="" value="submit">
</form>

我尝试了你的解决方案,使用GET和POST路由,但只有GET路由能够正常工作。你有什么线索可以解释这种情况吗?res.status(200).send(req.session)在条件块内部,不应该出现异步/问题之类的情况。我在这里发布了我的方法和收到的输出:https://pastebin.com/3N73huuC - Julio
你确定吗?这对我有效。你能检查一下更新吗?@Julio - Ahmed Can Unbay
也许尝试移除 status(200) - Ahmed Can Unbay
我已经尝试了一段时间不同的方法,只有在表单中使用action="link/to/the/api"时才有效。但是当我在onSubmit事件中使用我的AJAX调用时,它不起作用,req.session.isLoggedIn没有被存储。这里是我的React组件和handleSubmit方法。直接使用action="link-to-api"的问题是我会收到一个带有cookie信息的空白屏幕,我无法处理它(或者至少,我不知道如何像我在这里留下的pastebin那样处理)。提前感谢@turmuka! - Julio
我刚刚解决了我的问题,并发布了解决方案。无论如何,我想感谢你花时间帮助我解决问题,通过你的答案,我学到了一些新东西。 - Julio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接