使用Express后端和express-session的React应用程序

22

我目前拥有一个通过create-react-app创建的React应用程序和一个用于处理API调用的Express服务器。它们分别运行并且一直正常工作,直到我遇到了这个问题:

我还使用express-sessionpassport进行用户身份验证。我能够验证用户,但是会话在API调用之间不会持久化。如果我成功登录,下次进行API调用时,req.sessionID将不同,并且req.isAuthenticated()将返回false

这是我的服务器代码:

'use strict'

var express         = require('express');
var path                = require('path');
var bodyParser      = require('body-parser');
var cookieParser    = require('cookie-parser');
var mongoose      = require('mongoose');
var passport      = require('passport');
var session       = require('express-session');
var cors          = require('cors');
var flash         = require('connect-flash');

var store         = require('./store');
var database      = require('./database');

var app     = express();
var port    = process.env.port || 3001;
var router  = express.Router();

var promise = mongoose.connect('mongodb://localhost:27017/lifeless-db', {useMongoClient: true});

//app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser('lifeless-secret-01890'));
app.use(session({
  secret: 'lifeless-secret-01890',
  saveUninitialized: true,
  cookie: {
    secure: false,
  }
}));
app.use(flash());

app.use(passport.initialize());
app.use(passport.session());
// Initialize Passport
var authinit = require('./auth/init');
authinit(passport);

// For debugging:
app.use(function(req, res, next) {
  console.log("SessionID: " + req.sessionID);
  console.log(req.isAuthenticated() ? "This user is logged in" : "This user is NOT logged in");
  next();
});



// GET

app.get('/items', function(req, res) {
  store.getAllItems((items) => {
    if(!items) return res.send({error: true, message: 'Error loading store :/', items: null});
    else return res.send({error: false, message: 'Success', items: items});
  });
});

app.get('/login', function(req, res) {
  console.log(req.flash());
  console.log("Login fail");
  res.send({error: true, message: 'Unknown error'});
});


// POST

app.post('/message', function(req, res) {
  database.submitMessage(req.body.email, req.body.message, (success) => {
    if (success) return res.send({error: false, message: 'Success'});
    else return res.send({error: true, message: 'Error sending message'});
  });
});


app.post('/login', passport.authenticate('local', {failureRedirect: '/login', failureFlash: true}), function(req, res) {
  console.log(req.flash());
  console.log("Login success");
  return res.send({error: false, message: 'Success'});
});



// SERVER

app.listen(port, function(){
  console.log('Server started.');
  console.log('Listening on port ' + port);
});

下面是 React 应用程序中使用 axios 进行 API 调用的示例:

login(e) {
    e.preventDefault();

    axios({
      method: 'post',
      url: 'http://localhost:3001/login',
      data: {
        username: this.state.username,
        password: this.state.password,
      }
    })
    .then((response) => {
      console.log(response.data);
      if (response.data.error) {
        this.setState({error: true, errmessage: response.data.message});
      } else {
        this.setState({redirect: true});
      }
    })
    .catch((error) => {
      this.setState({error: true, errmessage: 'Error logging in'});
    });
  }

我想必须有一种方式让React以某种方式存储会话(?),但我对React比较新,并不真的知道如何将其与Express后端一起使用。


您需要使用数据存储配置app.session()以存储cookie,以便会话持久化。请参见此答案:https://dev59.com/c2Qo5IYBdhLWcg3wbe7r和https://dev59.com/Xmkw5IYBdhLWcg3wEmWb(还有许多其他解决此问题的答案)。 - Tom Oakley
我现在遇到了这个问题。两年过去了,没有人发表答案。@drewpel,你有解决方案吗?我猜这与标头有关。 - M312V
2个回答

4

你的React客户端的axios请求需要使用withCredentials发送。要解决这个问题,可以执行以下任一操作:axios.defaults.withCredentials = true; 或者 axios.get('url', {withCredentials: true})... 同时在你的Express.js后端中,设置cors选项 credentials: true


1
谢谢。我为这个解决方案卡了2个小时。 - Mejan
嗨,我在这个护照会话中卡住了。我也创建了一个问题。请检查此链接https://dev59.com/KMTra4cB1Zd3GeqP1kBz,并告诉我我错过了什么。 - user1187

0
这是一个使用connect-redis设置express-session的示例。首先,设置express-session和Redis存储。
var session = require('express-session);
var RedisStore = require('connect-redis')(session);  

然后,在你为应用程序声明中间件的地方;
app.use(session({
  store: new RedisStore({
    url: process.env.REDIS_URL
  }),
  secret: process.env.REDISSECRET,
  resave: false,
  saveUninitialized: false
}));

现在当您使用 req.session.{etc} 时,它会写入您的 Redis 数据库。


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