Node.js + express.js + passport.js: Bleiben Sie zwischen dem Neustart des Servers authentifiziert

75

Ich verwende passport.js, um die Authentifizierung in meiner Anwendung nodejs + express.js zu verarbeiten. Ich habe eine LocalStrategy eingerichtet, um Benutzer von Mongodb zu übernehmen

Mein Problem ist, dass Benutzer sich erneut authentifizieren müssen, wenn ich meinen Knotenserver neu starte . Dies ist ein Problem, da ich es aktiv entwickle und mich nicht bei jedem Neustart anmelden möchte ... (+ Ich verwende Node Supervisor)

Hier ist mein App-Setup:

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);
});

Und Setup der Sitzungsserialisierung:

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

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

Ich habe die in einem Blog angegebene Lösung (den Link wurde entfernt, da er nicht mehr existiert) mit connect-mongodb ohne Erfolg ausprobiert

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

EDIT zusätzliches Problem: Es sollte nur eine Verbindung hergestellt werden (Nutzung eines verbindungsbeschränkten mongohq-freien Dienstes)

EDIT 2- Lösung (als Edition ist mein Ruf zu niedrig, um meine Frage jetzt zu beantworten

Hier ist die Lösung, die ich endlich gefunden habe, indem ich eine von Mungos initiierte Verbindung verwendet habe

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');
        })
}));
Arnaud Rinquin
quelle
Nur zu Ihrer Information: Dieser Blog-Link hat mich zu einer unscharfen Dating-Site weitergeleitet ... Ich weiß nicht, ob es noch gut ist.
Anthonylawson
1
Oh ok, ich habe den Link entfernt.
Arnaud Rinquin
12
Entwickler erstellen unscharfe Dating-Sites.
Jim Schubert
Ich habe ein ähnlich entgegengesetztes Problem. Benutzer müssen nach dem Neustart des Browsers erneut authentifizieren. Hattest du dieses Problem?
sasha.sochka
1
RTFM möglicherweise: github.com/expressjs/session > Standardmäßig ist cookie.maxAge null, was bedeutet, dass kein "expires" -Parameter festgelegt ist, sodass das Cookie zu einem Browser-Sitzungscookie wird. Wenn der Benutzer den Browser schließt, werden das Cookie (und die Sitzung) entfernt.
Arnaud Rinquin

Antworten:

55

Es gibt eine OpenSource namens connect-mongo , die genau das tut, was Sie brauchen - die Sitzungsdaten in mongodb bleiben erhalten

Anwendungsbeispiel (mit Wiederverwendung einer mongoosegeöffneten Verbindung):

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}
    )        
}));

Weitere Informationen finden Sie hier: https://github.com/kcbanner/connect-mongo

Arnaud Rinquin
quelle
1
Arnaud, danke, ich habe die gleichen Probleme. Können Sie die Datenbank genauer angeben: mongoose.connection.db? Ich bin mir nicht sicher, was das bedeutet.
Jacques Tardie
Es tut mir leid für die späte Antwort, ich reise von Mexiko nach Frankreich zurück, ich werde in 48 Stunden mehr verfügbar sein. Antwort: Nun, Sie müssen die Mongo-Verbindungsinstanz an connect-mongodb übergeben, nachdem sie von mongoose initialisiert wurde. mongoose.connection.db ist die Instanz, über die wir sprechen. Wir übergeben sie über das Attribut "db" an connectdb.
Arnaud Rinquin
Los geht's Beachten Sie, dass es sich um einen alten Code handelt, der an neue APIs angepasst werden muss.
Arnaud Rinquin
4
{db:mongoose.connection.db} nicht funktioniert . Sie können verwenden, {mongooseConnection:mongoose.connection}was tatsächlich funktioniert
lmaooooo
6

Ich benutze Connect-Mongo wie folgt:

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());
Toxinlabs
quelle
Vielen Dank, aber ich habe ein zusätzliches Problem: Ich möchte nur eine Verbindung in meiner Datenbank, da ich den kostenlosen Mongohq-Dienst verwende (nur eine Verbindung).
Arnaud Rinquin
Ok, hier ist die endgültige, saubere Lösung mit Connect-Mongodb und Wiederverwendung der Mungo-Verbindung
Arnaud Rinquin
5

Dies liegt daran, dass Sie MemoryStore (Standard) für Sitzungen verwenden. Sehen Sie sich diesen Code aus memory.js (Teil des Connect-Frameworks) an:

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

und dieses Snippet aus session.js (Express)

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

Jetzt sollten Sie verstehen, dass jeder Serverneustart den MemoryStore zurücksetzt. Um die Daten zu behalten, müssen Sie einen anderen Sitzungsspeicher verwenden. Sie können sogar Ihre eigenen schreiben (sollte nicht zu schwierig sein), obwohl Redis (siehe diese Bibliothek ) eine gute Wahl sein könnte (und von Express gut unterstützt wird).

// BEARBEITEN

Nach der Connect - Dokumentation ist es genug für Sie , wenn Sie implementieren get, setund destroyMethoden. Der folgende Code sollte funktionieren:

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
}));

Sie müssen nur das Aufrufen von MongoDb (oder einer anderen Datenbank, obwohl ich weiterhin die Verwendung von Nichtpermament-Datenbanken wie Redis empfehle) zum Speichern von Sitzungsdaten implementieren. Lesen Sie auch den Quellcode anderer Implementierungen, um die Idee zu verstehen.

verrückt
quelle
1
Vielen Dank. Wie Sie sehen können, habe ich versucht, connect-mongodb (und connect-mongo) ohne Erfolg zu verwenden. Die Sitzungen werden nicht in meiner Datenbank gespeichert.
Arnaud Rinquin
1
@ArnaudRinquin Sorry, irgendwie habe ich das nicht gesehen. :) Ich habe die Antwort aktualisiert. Ich kenne weder Connect-Mongodb noch Connect-Mongo (ich verwende Mungo mit Redis als Sitzungsspeicher). Der einzige Rat, den ich für Sie habe, lautet: Versuchen Sie, den Sitzungsspeicher selbst zu implementieren.
freakish
Vielen Dank für Ihre Hilfe, aber ich habe die Lösung vor einigen Minuten gefunden und Ihre Antwort gesehen, als ich die Lösung veröffentlichen wollte.
Arnaud Rinquin
1
@ArnaudRinquin Sie wissen, dass Sie Ihre eigene Frage beantworten und als akzeptiert markieren können? Denn um ehrlich zu sein, hilft meine Antwort wenig. :)
freakish
Ich weiß, aber mein Ruf war zu niedrig. Ich werde es so schnell wie möglich tun. Danke für deine Ehrlichkeit.
Arnaud Rinquin
2

Dies ist wahrscheinlich für erfahrene Knotenbenutzer offensichtlich, hat mich aber überrascht:

Sie müssen die Knotensitzung konfigurieren - z

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

vor dem Initialisieren der Pass-Sitzung - z

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

Wenn Sie zuerst passport.session () aufrufen, funktioniert dies nicht (und Sie werden nicht gewarnt). Ich dachte, das Problem liege in der Serialisierung / Deserialisierung der Benutzerfunktionen und der verschwendeten Stunden.

Harryrobbins
quelle
1

Ich benutze Mungo, habe den in den obigen Antworten angegebenen Code ausprobiert und er hat bei mir nicht funktioniert. Ich habe diesen Fehler bekommen, als ich tat:

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

Dies funktioniert jedoch für mich:

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

Hinweis: Wenn Sie MongoStore aus irgendeinem Grund nicht haben, müssen Sie Folgendes tun:

npm install connect-mongo --save

dann:

var MongoStore = require('connect-mongo')(express)
arg20
quelle
1

Was ich letztendlich gemacht habe:

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
    })
}));

Funktioniert bei mir.

Kevin Suttle
quelle
1

Sie müssen den Speicher ändern, den Sie für Ihre Sitzungen verwenden. Der Standardspeicher 'MemoryStore' speichert die Sitzung nicht weiter, wenn Ihre Anwendung beendet wird. Schauen Sie sich die Express-Session auf Github an, um mehr darüber zu erfahren, welche anderen Geschäfte es gibt, wie die Mongo. (Kann mich nicht an den Namen erinnern)

James Brian Lago
quelle