Проблема
Я настраиваю свое приложение NodeJS и Express, используя Passport для аутентификации с помощью входа в Google и Facebook. При работе на локальном хосте все работает очень хорошо, но когда я развертываю свое приложение (на Vercel), я не могу заставить сеансы работать.
Процесс входа работает очень хорошо, и я могу видеть информацию о пользователе, прикрепленную к req.session
и req.user
содержат всю информацию о пользователе.
Однако сразу после этого при вызове любого маршрута req.user
будет undefined
Код
//Setting up the app
const express = require('express');
//const https = require('https');
//Bodyparser to handle JSON
const bodyParser = require('body-parser');
//Mongoose to connect to MongoDB
const mongoose = require('mongoose');
//To handle environments
const keys = require('./keys')
//To handle user sessions
var session = require("express-session");
var MongoDBStore = require('connect-mongodb-session')(session);
//Passport to hangle Google Sign In
var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
//Authentication: serialize and deserialize user
passport.serializeUser(function(user, done) {
console.log(`serialize: user:${user}`);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
console.log(`deserialize user:${user}`)
done(err, user);
});
});
//Authentication: Google Sign In
passport.use(new GoogleStrategy({
clientID: keys.GOOGLE_CLIENTID,
clientSecret: keys.GOOGLE_SECRET,
callbackURL: keys.URL_GOOGLE_CALLBACK
},
function callback(accessToken, refreshToken, profile, done) {
process.nextTick( ()=> {
User.findOne({'googleId': profile.id}, (err,user)=> {
if(err)
return done(err,false);
if(user){
return done(null, user);
}
else{
var newUser = new User();
newUser.googleId = profile.id;
newUser.googleToken = accessToken;
newUser.firstName = profile.name.givenName;
newUser.email = profile.emails[0].value;
newUser.authType = "Google";
newUser.image = profile.photos[0].value;
newUser.save((err)=> {
if(err)
throw err;
return done(null, newUser);
});
}
});
});
}
));
//Importing the models used
const Country = require('./models/country');
const Place = require('./models/place');
const User = require('./models/user');
const Trip = require('./models/trip');
//Starting the app
const app = express();
//Using body parser as global middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }))
//Using cookie bodyParser
app.use(require('cookie-parser')('keyboard cat'))
//Using Cors for routes
//app.use(cors())
//Store for sessions
var storeSessions = new MongoDBStore({
uri: keys.URI_MONGO,
collection: 'sessions'
});
// Catch errors
storeSessions.on('error', function(error) {
console.log(error);
});
//Added but not sure if useful
app.use(cors({credentials: true, origin: true}));
app.set('trust proxy', 1);
//Setting up a session
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: false,
proxy: true,
store: storeSessions,
cookie : {
maxAge: 2419200000
}
}));
//Using passport for authentication
app.use(passport.initialize());
app.use(passport.session());
//Solving CORS issues
app.use((req, res, next) => {
let allowedOrigins = ['http://localhost:3000', 'http://localhost:8080', 'mywebsite.com'];
let origin = req.headers.origin;
if(allowedOrigins.indexOf(origin) > -1){
res.setHeader('Access-Control-Allow-Origin', origin);
}
//res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
res.header('Access-Control-Allow-Credentials', true);
next();
});
//Connection to MongoDB
mongoose.connect(keys.URI_MONGO, {useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('Connection successful!'))
.catch((error) => { console.error(error); });
//The API call from the Google sign in button
app.get('/authgoogle',
passport.authenticate('google', { scope : ['profile', 'email'] }));
//Callback from Google Sign in
app.get('/authgoogleredirect', function(req, res, next) {
passport.authenticate('google', {
scope : ['profile', 'email']
}, function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect(keys.URL_SIGN_IN); }
req.logIn(user, function(err) {
if (err) { return next(err); }
req.session.user = req.user;
req.session.save(function(){
console.log(`req.session.user in callback: ${req.session.user}`)
console.log(`req.session in callback: ${JSON.stringify(req.session)}`)
res.redirect(keys.URL_LOGGED_IN);
});
});
})(req, res, next);
});
//Middleware to check if user is logged in
function isLoggedIn(req, res, next) {
console.log(`req.session in isloggedin: ${JSON.stringify(req.session)}`);
console.log(`req.user in isloggedin: ${JSON.stringify(req.user)}`);
if (req.isAuthenticated()) {
next();
} else {
data = {
"redirect": true,
"url": keys.URL_SIGN_IN
}
res.send(JSON.stringify(data));
}
}
//--------------------USERS------------------------
//Getting the currently logged in user
app.get('/getcurrentuser', isLoggedIn, function(req, res, next) {
res.send(req.user);
});
Что работает, а что нет
Вход в Google работает хорошо, а passport.serialize
и passport.deserialize
работают хорошо, я вижу объект пользователя.
Когда я пытаюсь для доступа к GET / getcurrentuser (вызов на всех страницах) я не получаю объект req.user и isAuthenticated()
всегда возвращает false
.
Это журналы промежуточного программного обеспечения isloggedin: req.session in isloggedin: {"cookie":{"originalMaxAge":2419200000,"expires":"2020-08-07T12:09:54.220Z","httpOnly":true,"path":"/"}}
req.user in isloggedin: undefined
Сеансы правильно сохранены в коллекции сеансов в mongoDB.
Кажется, что сериализация и десериализация не вызываются после входа в систему, не уверен, что это нормально.
Что я пробовал
Я прочитал много ответов на похожие проблемы ems, но ничего не работает:
- порядок инициализации паспорта и express сеанс : он должен быть правильным
- прокси : добавлено, но ничего не изменилось
- учетные данные : include всегда был включен в мой вызов выборки внешнего интерфейса
- cook ie .secure: false : включил и выключил, безуспешно
- повар ie сеанс пытался использовать его вместо express сеанса, безуспешно
Это должно быть что-то глупое, но я не могу его найти ... Меня беспокоит, почему это работает на localhost?
Большое спасибо за ваше время :)