当我通过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);
});
});
}
答案 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中的所有其他标头。一切都开始工作了。
弄清这个问题,今天我花了两个小时,希望这个答案对某人有帮助。