Knoten + Express + Pass: req.user Undefiniert


74

Meine Frage ist ähnlich wie diese ein , aber es gab keinen Einblick in seine Lösung.

Ich verwende Passport, um über Instagram zu authentifizieren. Nach erfolgreicher Authentifizierung werden Benutzer zu "/" weitergeleitet. Zu diesem Zeitpunkt hat die Anforderung das Benutzerobjekt (auch bekannt als es funktioniert). Sobald ich jedoch umleitung, ist der req.user undefiniert. : '(

Der seltsame Teil ist, dass passport.deserializeUser bei jeder Anforderung aufgerufen wird. Das Benutzerobjekt wird erfolgreich abgerufen, aber irgendwo auf der Middleware-Straße wird req.user nicht festgelegt (oder nicht festgelegt).

// on successful auth, goto "/" 
app.get('/', function(req, res) {
    // if the request has the user object, go to the user page
    if (req.user) {
        res.redirect("/user/" + req.user._id);
    }

    res.render("index");
}

app.get('/user/:uid', function(req, res) {
    console.log(req.user) // undefined
}

3
Könnten Sie die Konfiguration Ihrer App veröffentlichen? app.use(...)Besonders Middleware ( ). Es kann sein, dass Ihre Sitzungscookies einen zu geringen Ablauf haben oder dass die Reihenfolge der Middleware falsch ist.
Robertklep

Middleware-Bestellung ist höchstwahrscheinlich das Problem hier
Noah

1
Ich mache die Middleware genau so, wie sie auf der Passport-Konfigurationsseite erklärt wird, und habe immer noch das gleiche Problem:
vsync

1
Haben Sie jemals eine Lösung gefunden?
Erdbeere

1
Ich habe das gleiche Problem. Ich kann es nicht zum Laufen bringen und es scheint, dass der req.user jedes Mal zurückgesetzt wurde
Gang Su

Antworten:


46

Haben Sie den Sitzungsstatus für Ihre App eingerichtet? Du brauchst so etwas ...

app.use(session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());

22
Ich habe genau das getan, was Sie geschrieben haben, und ich bekomme auch die undefined Nachricht.
vsync

3
Denken Sie dies tatsächlich ist app.use(session({secret : 'anything'});jetzt , dass Express-Sitzung sein eigenes Paket und nicht Teil der Express
Gårds

2
Ich habe immer noch das Problem, nachdem ich expression eingerichtet habe. Ich rufe die Passfunktion nach der Initialisierung der Express-Sitzung auf und kann Sitzungen ohne Probleme in der App verwenden.
Pietro Coelho

@martin Wird passport.session()benötigt, wenn ich keine Sitzungen verwende?
Zlatko

2
Diese Lösung funktionierte für mich in dem Sinne, dass ich meine App-Konfigurationen in der falschen Reihenfolge hatte. Als ich sie in die oben angegebene Reihenfolge brachte, wurde das Problem behoben.
Fraxtur

57

Mein Problem bestand nicht darin, Cookies zu senden, wenn Fetch auf der Clientseite verwendet wird. Es funktionierte, nachdem das Feld "Anmeldeinformationen" in die Anforderung aufgenommen wurde.

fetch('/api/foo', {credentials: 'include'})

8
Verbrachte viel zu viel Zeit mit der Suche nach einer Lösung und versuchte, den Pass auf der Serverseite auf verschiedene Arten zu konfigurieren, nur um festzustellen, dass das Problem im clientseitigen Code lag. Danke für deine Antwort.
Anurag Awasthi

4
Warten Sie, wie ist dieser Tipp nicht leichter zu finden? Ich habe so viele Fragen und Antworten zu StackOverflow gelesen, bevor ich diese gefunden habe. Vielen Dank, Jon Rodness. Vielen Dank.
Tscizzle

Verbrachte 4 Stunden und rettete meinen anderen Tag oder so, kann auch ein Monat sein. : P
Thirunavukkarasu Muthuswamy

1
Um ein bisschen zu erweitern, werden solche Cookies standardmäßig nur gesendet, wenn die Anfrage vom selben Ursprung stammt. Andernfalls müssen Sie das withCredentialsFlag verwenden, um anzugeben, dass Cookies tatsächlich zurückgesendet werden sollen. Siehe developer.mozilla.org/en-US/docs/Web/API/Request/credentials . Beachten Sie auch, dass die Syntax anders ist, wenn Sie Axios anstelle der Abruf-API verwenden.
Adam Zerner

17

Ich bin super neu bei Node, aber es war ein Middleware-Problem für mich. BodyParser hinzugefügt und neu angeordnet, um das Problem zu beheben.

Defekter Code:

app.use(express.cookieParser('secret'));
app.use(express.cookieSession());
app.use(express.session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public'))); 

Arbeitscode:

app.use(express.static(path.join(__dirname, 'public')));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);

Hoffe das hilft


Das hat mir geholfen. Warum funktioniert die zweite Bestellung der Middleware und nicht die erste?
Sung Cho

Es gingen so viele Stunden verloren, als wir versuchten, das Ding auf verschiedene Arten zu debuggen, und alles lief darauf hinaus. habenexpress.static als einer der letzten Middleware war Brechen alles Auth für mich zusammen. es war nicht einmal konsequentes Verhalten, manchmal funktionierte es, manchmal nicht. Ich vermute, dass etwas im Express / Erwähnten Libs-Code sehr lückenhaft und anfällig für Rennbedingungen ist.
Vee6

12

Zuvor habe ich diesen Code (hat nicht funktioniert):

app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('abcdefg'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
    secret: 'abcdefg',
    resave: true,
    saveUninitialized: false,
    cookie: { secure: true } // this line
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));

Dann entferne ich die Cookie-Option aus dem Sitzungsinitialisierer:

app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('abcdefg'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
    secret: 'abcdefg',
    resave: true,
    saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));

und jetzt funktioniert es.


1
@Squirrl Sein Express-Server befand sich wahrscheinlich hinter einem Proxy (Heroku, Nginx, IISnode), der die SSL-Verbindung beendet. Das ist normal. Lesen Sie hier eine ausführliche Erklärung: stackoverflow.com/questions/33871133/…
Christiaan Westerbeek

5

Ich habe das gleiche Problem, weil ich nur den folgenden Code aus der Express-Sitzungsdokumentation kopiere und einfüge, aber die Dokumentation nicht vollständig lese.

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true }
}))

In der Dokumentation wurde Folgendes erwähnt:

Es ist jedoch eine https-fähige Website erforderlich, dh HTTPS ist für sichere Cookies erforderlich. Wenn sicher festgelegt ist und Sie über HTTP auf Ihre Site zugreifen, wird das Cookie nicht gesetzt.

Wenn Sie also nur eine HTTP-Verbindung haben, entfernen Sie die sichere Option. Der folgende Code sollte funktionieren:

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  //cookie: { secure: true } remove this line for HTTP connection
}))

Vielen Dank! Ich habe zwei Stunden verzweifelt darüber nachgedacht, nur um festzustellen, dass ich vor einigen Monaten Cookies auf HTTPS aktualisiert hatte und lokal über HTTP testete.
Miguelmorin

4

Ich hatte genau das gleiche Problem mit Express 4 und nachdem ich so ziemlich alles ausprobiert hatte, was ich online finden konnte, gelang es mir schließlich, es durch Hinzufügen einer "Cookie-Sitzung" zum Laufen zu bringen.

var cookieSession = require('cookie-session');

app.use(cookieSession({
  keys: ['key1', 'key2']
}));

4

Ja, aktiviere Sitzungen, wie @Martin sagt. Wenn Sie jedoch die Express 4. * -Version verwenden, werden Middleware-ähnliche Sitzungen nicht gebündelt, sodass Sie sie einzeln installieren müssen.

  1. Fügen Sie "express-session": "1.4.0" in Ihre package.json ein
  2. npm installieren
  3. benutze es

;;

var express = require('express');
var cookieParser = require('cookie-parser')
var session = require('express-session')
var app = express()
app.use(cookieParser()) // required before session.
app.use(session({secret: 'keyboard cat'}))

Weitere Informationen finden Sie in der Express-Sitzungsdokumentation.


Cookie Parser wird aufgrund der Dokumente, auf die Sie verlinken, nicht mehr empfohlen.
Counterbeing

3

Versuchen Sie in Routen Folgendes hinzuzufügen: {session: true}

app.get('/auto-login', passport.authenticate('cross', {session: true}))

1
Ich habe gerade ungefähr eine Stunde damit verbracht, die Interna des Passes zu debuggen, um zu dem gleichen Ergebnis zu kommen. req.userwird nicht festgelegt, wenn Sie session: falsein den Optionen Ihres Anrufs angeben passport.authenticate.
Evan Siroky

{ session: true }scheint Standard zu sein.
Flaudre

Seltsamerweise hat das auch bei mir funktioniert. Reisepass v0.3.2.
Hyubs

1
Ich verwende passport-twitterund setze Sitzung explizit funktioniert nicht für mich. In der gleichen App, passport-google-authdie genau die gleichen Codezeilen ausführt, ist in Ordnung.
Old Geezer

3

Wenn Sie einen Benutzer authentifizieren, wird der Anforderungswert req.usergefüllt. Um zu wissen, ob der Benutzer identifiziert und dieser Wert eingegeben wird, wird ein Cookie verwendet. Wenn Sie wie ich die Sitzung mit sicheren Cookies konfigurieren, sind Cookies nur über verfügbar. Dies HTTPSist nicht die Standardkonfiguration für beispielsweise einen lokalen Entwicklungsserver. Damit Cookies funktionieren HTTP, werden Kommentare cookie: { secure: true }und req.userWerte ordnungsgemäß konfiguriert:

this.app.use(session({
    resave: true,
    saveUninitialized: true,
    secret: process.env.SESSION_SECRET || "a secret",
    // cookie: { secure: true },
}));

Wenn Sie Cookies vernünftigerweise HTTPSnur in der Produktion verwenden möchten , können Sie Folgendes tun:

cookie: { secure: process.env.ENV === 'PRODUCTION' }

2
Ich danke dir sehr! Ich habe eine Weile unter diesem Problem gelitten.
Mathyou

Vielen Dank! Ich habe zwei Stunden verzweifelt darüber nachgedacht, nur um festzustellen, dass ich vor einigen Monaten Cookies auf HTTPS aktualisiert hatte und lokal über HTTP testete.
Miguelmorin

3

Ich denke, jeder hat mehrere Fehler auf der Serverseite, die dieses Problem verursachen können.

Um diesen Fehler zu beheben, überprüfen Sie bitte diese Dinge:

Check 1 - Passport Serialization and Deserialization

Der richtige Weg, es zu tun (Mungo):

passport.serializeUser((user, done) => {
    done(null, user._id);
});

passport.deserializeUser((_id, done) => {
  User.findById( _id, (err, user) => {
    if(err){
        done(null, false, {error:err});
    } else {
        done(null, user);
    }
  });
});

Überprüfen Sie 2 - Sitzungen

Überprüfen Sie, ob Ihr Cookie-Sitzungspaket ordnungsgemäß konfiguriert ist und funktioniert. Überprüfen Sie, ob auf der Clientseite tatsächlich Cookies angezeigt werden. Wenn Sie eine Express-Sitzung verwenden , stellen Sie bitte sicher, dass die Sitzungs-ID im Speicher oder im Cache (Redis) angezeigt wird.

Überprüfen Sie 3 - SSL Nginx

Stellen Sie sicher, dass Ihr Reverse-Proxy Cookies und den Anfragetyp unterstützt. Vergessen Sie nicht, die Cookie- / Sitzungskonfiguration zu überprüfen [secure Flag]

Wenn ich auf diesen Fehler stoße, habe ich die (user)Rückruffunktion verwendet. Dann habe ich es mit korrigiert (err, user). Jetzt ist alles in Ordnung. Prost 🍻


1
Vielen Dank! Ich habe zwei Stunden verzweifelt darüber nachgedacht, nur um festzustellen, dass ich vor einigen Monaten Cookies auf HTTPS aktualisiert hatte und lokal über HTTP testete.
Miguelmorin

1

Bei mir ging es um Kekse und Cors. Ich habe das Problem gelöst, indem ich meinem Server folgenden Code hinzugefügt habe:

allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000'); // your website
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if ('OPTIONS' === req.method) {
    res.send(200);
} else {
    next();
}};

1

Sobald Sie Ihre Express-Sitzung eingerichtet haben, stellen Sie sicher, dass Sie Passport serialize & deserialize haben. In der Deserialize-Funktion wird dann req.user generiert. Siehe Erklärung hier von einer anderen Stackoverflow-Frage.

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


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

1

Wenn Sie die http-Anforderung auf der Clientseite verwenden, denken Sie daran, Anmeldeinformationen anzuhängen. In Angular2 müssen Sie das Optionsargument {withCredentials: true} hinzufügen. Danach haben Sie dieselbe req.sessionID, bis Sie sie erneut zurücksetzen.

this._http.get("endpoint/something", { withCredentials: true })

1

Meins war anders als all diese. Ich hatte zuvor auf localhost eine Wordpress-Site entwickelt und dann zu einem separaten Node / React-Projekt gewechselt.

Das Cookie von der Wordpress-Site war noch vorhanden und wurde gesendet, da beide Projekte auf localhost ausgeführt wurden. Dies verursachte das Problem.

Ich musste die Cookies für localhost löschen und dann funktionierte es.


0

Wenn Ihre Middleware - Stack unklar ist, Sie Session - Middleware unter der Annahme haben irgendwo , können Sie die Sitzung vor der Umleitung speichern:

if (req.user) {
    req.session.save(function (err) {
        if (err) {
            // ... panic!
        }
        res.redirect("/user/" + req.user._id);
    });
    return;
}

0

Haben Sie versucht, Ihren secretKey in den CookieParser einzufügen?

var passport = require('passport');
var expressSession = require('express-session');

app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('mySecretKey'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(expressSession({
secret: 'mySecretKey',
  resave: false,
  saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());

0

Hatte genau das gleiche Problem. Für mich bestand die Lösung darin, "Client-Sitzungen" anstelle von "Express-Sitzungen" zu verwenden. Wahrscheinlich schlechte Sitzungskonfiguration?

Nicht funktionierender Code:

var session = require('express-session');

app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(session({
    secret: 'random string',
    resave: true,
    saveUninitialized: true,
    cookie: { secure: true }
}));

Arbeitscode:

var session = require('client-sessions');

        app.use(bodyParser.urlencoded({ extended: false }));
        app.use(express.static(path.join(__dirname, 'public')));
        app.use(cookieParser());
        app.use(bodyParser.json());
        app.use(session({
        cookieName: 'session',
        secret: 'random string',
        duration: 30 * 60 * 1000,
        activeDuration: 5 * 60 * 1000,
    }));

0

Ich hatte das gleiche Problem, sowohl mit req.isAuthenticated () als auch mit req.user. Hier ist, wie ich es gelöst habe

  • req.isAuthenticated () wurde behoben, indem findOne () durch find () in der findById () -Methode in deserialize () ersetzt wurde. Dann konnte ich authentifizierte req speichern, andernfalls wurde nichts zurückgegeben.

  • req.user durch Anpassen der Reihenfolge aufgelöst, zuerst sollte die Express-Sitzung gespeichert werden, dann sollte der Pass initialisiert werden, dann der nächste Sitzungsspeicher in passport.session () und danach können wir auf req.user zugreifen, nachdem wir die Sitzung in passport.session () gespeichert haben.

app.use(session(...));
app.use(passport.initialize());
app.use(passport.session());
// Now we can access req.user so after we will call req.user, if we write it above these, it will always return underfined
app.use(function(req, res, next){
  res.locals.user = req.user || null
  next();
})

Wenn Sie danach auf req.user zugreifen passport.session(), fügen Sie unten Ihre Route hinzu.


0

Währenddessen passport.authenticatekönnen Sie hinzufügen session: true, um Ihr Problem zu beheben:

app.post("/login", passport.authenticate('local', {
    'failureRedirect': '/login',
    'session': true
}), (req, res)=>{ res.redirect("/"); });

0

Meine zwei Cent: nicht funktionierender Code:

server.use(
session({
  secret: "secretsssss",
  rolling: false,
  resave: false,
  saveUninitialized: false,
  cookie: {
    sameSite: true, //this line
    maxAge: 60 * 60 * 1000
  }
})
);

Arbeitscode:

server.use(
session({
  secret: "secretsssss",
  rolling: false,
  resave: false,
  saveUninitialized: false,
  cookie: {
    sameSite: false, // i think this is default to false
    maxAge: 60 * 60 * 1000
  }
})
);

0

Der Server sendet den SetCookie-Header und dann das Browser-Handle, um ihn zu speichern. Anschließend wird das Cookie mit Anforderungen an denselben Server in einem Cookie-HTTP-Header gesendet.

Ich musste withCredentials: true in meinem Client festlegen. (axios.js)

const config = {
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
  },
};

axios.put(url, { page: '123' }, config)
  .then(res => console.log('axios', res))
  .catch(err => console.log('axios', err));

Dann treten CORS-Probleme auf.

Also habe ich dies meinem Express-Server hinzugefügt:

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');
  if ('OPTIONS' == req.method) {
    res.send(200);
  } else {
      next();
  }
});

0

Ich bin auf dasselbe Problem gestoßen, aber mein Problem hing eher mit einem Missverständnis des Unterschieds zwischen passport.authorizeund passport.authenticatezu Beginn der OAuth-Flow- und OAuth-Rückrufrouten zusammen.

passport.authorizeDie req.userVariable wird nicht beeinflusst , aber da ich nur den Beispielcode aus den Dokumenten der Strategie kopiert und eingefügt habe, habe ich nicht bemerkt, dass die falsche Methode verwendet wurde. Nach dem Wechsel zupassport.authenticate Benutzervariable war verfügbar.

Hoffe, dies hilft jedem, der unwissentlich das Gleiche tut.


0

Ändern Sie die Reihenfolge von diesem:

app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));

dazu:

app.use(bodyParser.urlencoded({ extended: true }));
app.set("view engine", "ejs");

Willkommen bei Stack Overflow. Von Nur-Code-Antworten wird bei Stapelüberlauf abgeraten, da sie nicht erklären, wie das Problem gelöst wird. Bitte bearbeiten Sie Ihre Antwort, um zu erklären, wie diese Änderung das Problem in der Frage behebt, sodass sie auch für andere Benutzer mit demselben Problem nützlich ist.
FluffyKitten

0

Ich habe den Cookie-Parser zusammen mit einer Express-Sitzung wie dieser verwendet:

var express = require("express"); // 4.16.1
var cors = require("cors"); // 2.8.5
var cookieParser = require("cookie-parser"); // 1.4.4
var expressSession = require("express-session"); // 1.17.1

var app = express();

app.use(
  cors({
    origin: "http://localhost:3000",
    credentials: true,
  })
);

app.use(express.json());
app.use(express.urlencoded({ extended: true }));


app.use(
  expressSession({
    secret: "secret123",
    resave: true,
    saveUninitialized: true,
    cookie: { maxAge: 60 * 60 * 24 * 1000 },
  })
);
app.use(cookieParser("secret123")); // this line

Das Setzen des Cookie-Parsers vor der Express-Sitzung hat bei mir folgendermaßen funktioniert:

var express = require("express"); // 4.16.1
var cors = require("cors"); // 2.8.5
var cookieParser = require("cookie-parser"); // 1.4.4
var expressSession = require("express-session"); // 1.17.1

var app = express();

app.use(
  cors({
    origin: "http://localhost:3000",
    credentials: true,
  })
);

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use(cookieParser("secret123"));
app.use(
  expressSession({
    secret: "secret123",
    resave: true,
    saveUninitialized: true,
    cookie: { maxAge: 60 * 60 * 24 * 1000 },
  })
);

-1

Ich hatte ein anderes Problem, etwas mit bcrpt-Node- und Pfeilfunktionen.

Code, der funktioniert:

userSchema.methods.generateHash = function (password) {
  return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); 
};

userSchema.methods.isValidPassword = function (password) {
  return bcrypt.compareSync(password, this.password);
};

Code, der nicht funktioniert:

userSchema.methods.generateHash = (password) => {
  return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};

userSchema.methods.isValidPassword = (password) => {
  return bcrypt.compareSync(password, this.password);
};
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.