永远不会使用Axios http请求调用Passport deserializeUser()

时间:2018-04-10 06:34:54

标签: javascript node.js express passport.js axios

当我通过axios向我的Express应用程序发送请求时,req.isAuthenticated()始终为false且req.user即使在登录后也不存在。但是当我通过Postman向应用程序发送请求时,它可以正常工作。似乎永远不会调用deserializeUser(),因此永远不会填充req.session.passport字段。

我已经在线尝试了所有建议,感谢任何帮助。

外部请求:

async tweet(content) {
    try {
      await axios.post(this.url + '/tweets/new', {
        content: content,
        withCredentials: true,
        headers: {
          'Content-Type': 'application/json',
        }
      });

    } catch (err) {
      console.log(err);
    }
}

index.js

const passport = require('passport');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const RedisStore = require('connect-redis')(session)
const redisCookie = require('heroku-redis-client');

require('./config/passport')(passport);

// required for passport
app.use(cookieParser());

app.use(session({
  // secret: process.env.SECRET || 'enteryoursecrethere',
  secret: 'enteryoursecrethere',
  cookie: { maxAge: 3600000 },
  resave: true,
  store: new RedisStore({client: redisCookie.createClient()}),
  saveUninitialized: true
}));

app.use(passport.initialize());
app.use(passport.session());

app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Origin', req.headers.origin);
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
  next();
});

router.js

var tweets = require('../controllers/tweets');
var router = express.Router();
var isLoggedIn = require('../middleware/isLoggedIn');

router.post('/tweets/new', isLoggedIn, tweets.tweet);

中间件/ isLoggedIn.js

module.exports = (req, res, next) => {
    // If user is authenticated in the session, carry on.
    if (req.isAuthenticated()) {
      next();
      return
    }

    // If they aren't redirect them to the home page.
    res.redirect('/');
}

passport.js

const LocalStrategy = require('passport-local').Strategy;
const User = require('../models').User;
const Sequelize = require('sequelize');

module.exports = function(passport) {
  // The login request establishes a session maintained in a browser cookie.
  // Requests after the login request not contain credentials,
  // but rather the unique cookie that identifies the session. The user object
  // is constructed to and from the ID in the cookie.

  // Converts user to user id.
  passport.serializeUser(function(user, done) {
    done(null, user.id);
  });

  // Converts user id to user, stored in req.user.
  passport.deserializeUser(function(id, done) {
    User.findById(id).then(function(user) {
      done(null, user);
    }).catch(function(err) {
      done(err);
    });
  });

  /* ============Login============ */
  passport.use('local-login', new LocalStrategy({
    usernameField: 'username',
    passwordField: 'password',
    passReqToCallback : true // Send entire request for flash message.
  }, loginCallback));

  passport.use('local-signup', new LocalStrategy({
    usernameField: 'username',
    passwordField: 'password',
    passReqToCallback : true
  }, signupCallback));

};

function loginCallback(req, username, password, done) {
  if (req.isAuthenticated()) {
    return done(null, req.user);
  }
  // Look up the user by username.
  User.findOne({
    where: {
      username: username
    }
  }).then(function(user) {
    if (!user) {
      return done(null, false, req.flash('loginUsernameMessage', 'Wrong username.'));
    }

    if (!user.validatePassword(password)) {
      return done(null, false, req.flash('loginPasswordMessage', 'Wrong password.'));
    }

    return done(null, user.get());
  }).catch(function(err) {
    return done(err);
  });
}

function signupCallback(req, username, password, done) {
  // Asynchronous. User.findOne wont fire unless data is sent back.
  process.nextTick(function() {
    if (password != req.body.password_confirm) {
      return done(null, false, req.flash('signupMessage', 'Passwords don\'t match.'));
    }

    // Find a user whose email is the same as the forms email.
    // We are checking to see if the user trying to login already exists.
    User.findOne({
      where: {
        [Sequelize.Op.or]: [ { username: username }, { email: req.body.email }]
      }
    }).then(function(user) {
      // Check to see if theres already a user with that username or email.
      if (user) {
        return done(null, false, req.flash('signupMessage', 'That email or username is already taken.'));
      }
      // Create the user.
      var data = {
        fname: req.body.fname,
        lname: req.body.lname,
        username: username,
        email: req.body.email,
        password: User.generateHash(password)
      }

      User.create(data).then(function(newUser) {
        return done(null, newUser);
      }).catch(function(err) {
        return done(err);
      });
    }).catch(function(err) {
      return done(err);
    });
  });
}

2 个答案:

答案 0 :(得分:0)

它仅适用于邮递员,因为会话是在服务器(快速)设置的,而不是在客户端(axios)。

因此,当您从axios请求时,它不知道会话是否已在服务器上设置。因此,您需要将凭据来源与请求一起发送。像这样修改您的请求:

await axios.post(this.url + '/tweets/new', {
    content: content,
    withCredentials: true,
    headers: {
      'Content-Type': 'application/json',
    },
    credentials: "same-origin"
  });

有关详细信息,请参阅this

答案 1 :(得分:0)

这个问题已经有一年了,但是我花了一点时间来使用Node / Express / Passport / React和本地策略以及Express会话来解决这个问题。

对我来说,将其添加到标题中:

withCredentials:true

还不够。 did 触发了CORS问题,但实际上并没有使axios发送带有请求的会话cookie。

这将导致以下情况:登录将创建会话,但是将永远不会调用反序列化功能,并且req.user始终为空。

这是解决此问题的方法:

在我的React组件构造函数中,我添加了以下代码行:

axios.defaults.withCredentials = true;

解决了。

事实上,它修复得非常好,以至于我能够删除Axios中的所有其他标头。一切都开始工作了。

弄清这个问题,今天我花了两个小时,希望这个答案对某人有帮助。