Node.js + express.js + паспорт.js: залишається автентифікованим між перезапуском сервера


75

Я використовую Passport.js для обробки автентифікації в моїй програмі nodejs + express.js. Я налаштував LocalStrategy для прийому користувачів з mongodb

Мої проблеми полягають у тому, що користувачі повинні повторно пройти автентифікацію, коли я перезапускаю свій сервер вузлів . Це проблема, оскільки я активно її розробляю і не хочу входити під час кожного перезапуску ... (+ я використовую нагляд за вузлом)

Ось установка мого додатка:

app.configure(function(){
    app.use('/static', express.static(__dirname + '/static'));
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({secret:'something'}));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(app.router);
});

І налаштування серіалізації сеансу:

passport.serializeUser(function(user, done) {
    done(null, user.email);
});

passport.deserializeUser(function(email, done) {
    User.findOne({email:email}, function(err, user) {
        done(err, user);
    });
});

Я спробував рішення, подане в блозі (видалив посилання, оскільки його більше не існує), використовуючи connect-mongodb без успіху

app.use(express.session({
    secret:'something else',
    cookie: {maxAge: 60000 * 60 * 24 * 30}, // 30 days
        store: MongoDBStore({
        db: mongoose.connection.db
    })
}));

РЕДАКТУВАТИ додаткову проблему: слід встановити лише одне підключення (використання одного безкоштовного сервісу Mongohq з обмеженим з'єднанням)

Рішення EDIT 2 (як видання, як я вважаю, моя репутація поки що низька, щоб відповісти на моє запитання

Ось рішення, яке я нарешті знайшов, використовуючи з'єднання, ініційоване мангустом

app.use(express.session({
    secret:'awesome unicorns',
    maxAge: new Date(Date.now() + 3600000),
    store: new MongoStore(
        {db:mongoose.connection.db},
        function(err){
            console.log(err || 'connect-mongodb setup ok');
        })
}));

Просто FYI: це посилання на блог перенаправило мене на химерний сайт знайомств ... Не знаю, чи це вже добре.
anthonylawson

1
О гаразд, я видалив посилання.
Арно Рінкін 15.03.13

12
Розробники роблять дрібні сайти знайомств.
Jim Schubert

У мене така ж протилежна проблема. Користувачі повинні повторно авторизуватися після перезапуску браузера. У вас була ця проблема?
sasha.sochka

1
Можливо, RTFM: github.com/expressjs/session > За замовчуванням cookie.maxAge має значення null, тобто параметр "закінчується" не встановлений, тому файл cookie стає файлом cookie сеансу браузера. Коли користувач закриє браузер, файл cookie (і сеанс) буде видалено.
Арно Рінкін

Відповіді:


55

Існує відкритий джерело з назвою connect-mongo, який робить саме те, що вам потрібно - зберігає дані сеансу в mongodb

Приклад використання (з повторним використанням mongooseвідкритого з'єднання):

var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/sess');
app.use(express.session({
    secret:'secret',
    maxAge: new Date(Date.now() + 3600000),
    store: new MongoStore(
    // Following lines of code doesn't work
    // with the connect-mongo version 1.2.1(2016-06-20).
    //    {db:mongoose.connection.db},
    //    function(err){
    //        console.log(err || 'connect-mongodb setup ok');
    //   }
    {mongooseConnection:mongoose.connection}
    )        
}));

Ви можете прочитати більше про це тут: https://github.com/kcbanner/connect-mongo


1
Арно, дякую, у мене такі ж проблеми. Чи можете ви бути більш чіткими щодо db: mongoose.connection.db? Я не впевнений, що це означає.
Жак Тарді

Мені шкода за пізню відповідь, я їду назад із Мексики до Франції, і я стану доступнішим через 48 годин. Відповідь: Ну, ви повинні передати екземпляр підключення mongo до connect-mongodb після того, як його ініціалізував mongoose. mongoose.connection.db - це екземпляр, про який ми говоримо, ми передаємо його в connectdb через атрибут "db".
Арно Рінкін

Ось вам зауважте, що це старий код, тому його потрібно адаптувати до нових API.
Арно Рінкін

4
{db:mongoose.connection.db} не працює . Ви можете використовувати те, {mongooseConnection:mongoose.connection}що насправді працює
lmaooooo

6

я використовую connect-mongo так:

var MongoStore = require('connect-mongo');

var sess_conf = {
  db: {
    db: mydb,
    host: localhost,
    collection: 'usersessions' // optional, default: sessions
  },
  secret: 'ioudrhgowiehgio'
};

 app.use(express.session({
    secret: sess_conf.secret,
    maxAge: new Date(Date.now() + 3600000),
    store: new MongoStore(sess_conf.db)
  }));


[...]

// Initialize Passport!  Also use passport.session() middleware, to support
  // persistent login sessions (recommended).
  app.use(passport.initialize());
  app.use(passport.session());

Дякую, але у мене є додаткова проблема: я хочу лише одне підключення у своїй базі даних, оскільки я використовую безкоштовну послугу mongohq (лише одне підключення).
Арно Рінкін

Гаразд, ось остаточне, чисте рішення за допомогою connect-mongodb та повторного використання
мангустського

5

Це тому, що ви використовуєте MemoryStore (за замовчуванням) для сеансів. Подивіться на цей код із memory.js (частина фреймворку Connect):

var MemoryStore = module.exports = function MemoryStore() {
  this.sessions = {};
};

і цей фрагмент із session.js (Express)

function session(options){
    /* some code */
    , store = options.store || new MemoryStore
    /* some code */
}

Тепер ви повинні розуміти, що кожен перезапуск сервера скидає MemoryStore. Щоб зберегти дані, вам доведеться скористатися іншим сховищем сеансів. Ви навіть можете написати свій власний (це не повинно бути занадто складно), хоча Redis (див. Цю бібліотеку ) може бути гарним вибором (і це добре підтримується Express).

// РЕДАКТУВАТИ

Згідно з документацією Connect, вам достатньо, якщо ви реалізуєте get, setі destroyметоди. Наступний код повинен працювати:

customStore = {
    get : function(sid, callback) {
        // custom code, for example calling MongoDb
    },
    set : function(sid, session, callback) {
        // custom code
    },
    destroy : function(sid, callback) {
        // custom code
    }
}    

app.use(express.session({
    store: customStore
}));

Вам просто потрібно реалізувати виклик MongoDb (або будь-який інший Db, хоча я все-таки рекомендую використовувати непроникний, такий як Redis) для зберігання даних сеансу. Також прочитайте вихідний код інших реалізацій, щоб зрозуміти ідею.


1
Дякую. Як бачите, я намагався використовувати connect-mongodb (і connect-mongo) без успіху, сеанси не зберігаються в моїй базі даних.
Арно Рінкін

1
@ArnaudRinquin Вибачте, я якось цього не бачив. :) Я оновив відповідь. Я не знайомий ні з connect-mongodb, ні з connect-mongo (я використовую mongoose з Redis як сховище сеансів), тому єдина порада, яку я маю для вас, полягає в наступному: спробуйте реалізувати сховище сесій самостійно.
чудернацький

Дякуємо за допомогу, але я знайшов рішення кілька хвилин тому і побачив вашу відповідь, оскільки хотів опублікувати рішення.
Арно Рінкін

1
@ArnaudRinquin Ви знаєте, що можете відповісти на власне запитання та позначити його як прийняте? Тому що, чесно кажучи, моя відповідь мало що може допомогти. :)
чудернацький

Я знаю, але моя репутація була занадто низькою. Я зроблю це якомога швидше. Дякую за вашу чесність.
Арно Рінкін

2

Це, мабуть, очевидно для досвідчених користувачів вузлів, але мене це зачепило:

Вам потрібно налаштувати сеанс вузла - наприклад

app.use(session({secret: "this_is_secret", store: ...}));

перед ініціалізацією сеансу паспорта - напр

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

Якщо ви спочатку зателефонуєте паспорту.session (), це не спрацює (і не попередить). Я думав, що проблема полягає в серіалізації / десеріалізації користувацьких функцій та втраті годин.


1

Я використовую мангуст, я спробував код, представлений у відповідях вище, і він не працював для мене. Я отримав цю помилку, коли зробив:

Error: db object already connecting, open cannot be called multiple times

Однак це працює для мене:

app.use(express.session({
    secret:'secret',
    maxAge: new Date(Date.now() + 3600000),
    store: new MongoStore({mongoose_connection:mongoose.connection})
}))

Примітка: Якщо у вас немає MongoStore з будь-якої причини, вам потрібно зробити:

npm install connect-mongo --save

тоді:

var MongoStore = require('connect-mongo')(express)

1

Що я закінчив робити:

var expressSession = require('express-session');
var redisClient = require('redis').createClient();
var RedisStore = require('connect-redis')(expressSession);
...
app.use(expressSession({
    resave: true,
    saveUninitialized: true,
    key: config.session.key,
    secret: config.session.secret,
    store: new RedisStore({
        client: redisClient,
        host: config.db.host,
        port: config.db.port,
        prefix: 'my-app_',
        disableTTL: true
    })
}));

Працює для мене.


1

Вам потрібно змінити магазин, який ви використовуєте для своїх сеансів. За замовчуванням «MemoryStore» не продовжує зберігати сеанс, коли програма зупиняється. Перевірте експрес-сесію на github, щоб дізнатись більше про те, які інші магазини існують, як магазин mongo. (Не пам’ятаю назву)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.