webentwicklung-frage-antwort-db.com.de

Weiterleitung zur vorherigen Seite nach Authentifizierung in node.js mit passport.js

Ich versuche, einen Anmeldemechanismus mit node.js, express und passport.js einzurichten. Das Login selbst funktioniert ganz gut, auch Sitzungen werden mit redis schön gespeichert, aber ich habe einige Probleme damit, den Benutzer dorthin umzuleiten, wo er angefangen hat, bevor er zur Authentifizierung aufgefordert wurde.

z.B. Benutzer folgt Link http://localhost:3000/hidden Wird dann zu http://localhost:3000/login Umgeleitet, aber dann möchte ich, dass er wieder zurück zu http://localhost:3000/hidden Umgeleitet wird.

Wenn der Benutzer willkürlich auf eine Seite zugreift, auf die er zuerst eingeloggt werden muss, wird er mit seinen Anmeldeinformationen auf die/login-Site umgeleitet und anschließend auf die Site zurückgeleitet, auf die er zuvor versucht hat, zuzugreifen.

Hier ist mein Login-Beitrag

app.post('/login', function (req, res, next) {
    passport.authenticate('local', function (err, user, info) {
        if (err) {
            return next(err)
        } else if (!user) { 
            console.log('message: ' + info.message);
            return res.redirect('/login') 
        } else {
            req.logIn(user, function (err) {
                if (err) {
                    return next(err);
                }
                return next(); // <-? Is this line right?
            });
        }
    })(req, res, next);
});

und hier meine sureAuthenticated Methode

function ensureAuthenticated (req, res, next) {
  if (req.isAuthenticated()) { 
      return next();
  }
  res.redirect('/login');
}

welches sich in die Seite /hidden einhakt

app.get('/hidden', ensureAuthenticated, function(req, res){
    res.render('hidden', { title: 'hidden page' });
});

Die HTML-Ausgabe für die Anmeldeseite ist recht einfach

<form method="post" action="/login">

  <div id="username">
    <label>Username:</label>
    <input type="text" value="bob" name="username">
  </div>

  <div id="password">
    <label>Password:</label>
    <input type="password" value="secret" name="password">
  </div>

  <div id="info"></div>
    <div id="submit">
    <input type="submit" value="submit">
  </div>

</form>
91
Alx

Ich weiß nichts über Reisepass, aber hier ist, wie ich es mache:

Ich habe eine Middleware, die ich mit app.get('/account', auth.restrict, routes.account) verwende und die redirectTo in der Sitzung setzt ... dann leite ich zu/login um

auth.restrict = function(req, res, next){
    if (!req.session.userid) {
        req.session.redirectTo = '/account';
        res.redirect('/login');
    } else {
        next();
    }
};

Dann in routes.login.post Ich mache folgendes:

var redirectTo = req.session.redirectTo || '/';
delete req.session.redirectTo;
// is authenticated ?
res.redirect(redirectTo);
74
chovy

Speichern Sie in Ihrer ensureAuthenticated -Methode die Rückgabe-URL in der Sitzung wie folgt:

...
req.session.returnTo = req.originalUrl; 
res.redirect('/login');
...

Dann können Sie Ihre passport.authenticate-Route folgendermaßen aktualisieren:

app.get('/auth/google/return', passport.authenticate('google'), function(req, res) {
    res.redirect(req.session.returnTo || '/');
    delete req.session.returnTo;
}); 
99
linuxdan

Schauen Sie sich connect-verify-login an, das neben Passport funktioniert, um genau das zu tun, was Sie wollen!

14
Jared Hanson

Wenn Sie connect-sure-login verwenden, gibt es eine sehr einfache, integrierte Möglichkeit, dies mit Passport unter Verwendung des Parameters successReturnToOrRedirect zu tun. Bei Verwendung sendet der Pass Sie an die ursprünglich angeforderte URL zurück oder greift auf die von Ihnen angegebene URL zurück.

router.post('/login', passport.authenticate('local', {
  successReturnToOrRedirect: '/user/me',
  failureRedirect: '/user/login',
  failureFlash: true
}));

https://github.com/jaredhanson/connect-ensure-login#log-in-and-return-to

5
igneosaur

Meine Art Dinge zu tun:

const isAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    return next()
  }
  res.redirect( `/login?origin=${req.originalUrl}` )
};

GET/login controller:

if( req.query.Origin )
  req.session.returnTo = req.query.Origin
else
  req.session.returnTo = req.header('Referer')

res.render('account/login')

POST/login controller:

  let returnTo = '/'
  if (req.session.returnTo) {
    returnTo = req.session.returnTo
    delete req.session.returnTo
  }

  res.redirect(returnTo);

POST/logout controller (nicht sicher, ob 100% in Ordnung sind, Kommentare sind willkommen):

req.logout();
res.redirect(req.header('Referer') || '/');
if (req.session.returnTo) {
  delete req.session.returnTo
}

ReturnTo Middleware löschen (Löscht ReturnTo von der Sitzung auf jeder Route außer Authentifizierungsrouten - für mich sind dies/login und/auth /: provider):

String.prototype.startsWith = function(needle)
{
  return(this.indexOf(needle) == 0)
}

app.use(function(req, res, next) {
  if ( !(req.path == '/login' || req.path.startsWith('/auth/')) && req.session.returnTo) {
    delete req.session.returnTo
  }
  next()
})

Dieser Ansatz hat zwei Funktionen:

  • sie können einige Routen mit isAuthenticated Middleware schützen.
  • Auf jeder Seite können Sie einfach auf die Anmelde-URL klicken und nach der Anmeldung zurück zu dieser Seite;
5
deksden

@chovy und @linuxdan Antworten haben Bug mit nicht löschen session.returnTo Wenn der Benutzer nach der Umleitung der Anmeldung zu einer anderen Seite wechselt (dies erfordert keine Authentifizierung) und sich dort anmeldet. Fügen Sie diesen Code zu ihren Implementierungen hinzu:

// clear session.returnTo if user goes to another page after redirect to login
app.use(function(req, res, next) {
    if (req.path != '/login' && req.session.returnTo) {
        delete req.session.returnTo
    }
    next()
})

Wenn Sie Ajax-Anforderungen von der Anmeldeseite ausführen, können Sie diese auch ausschließen.


Ein anderer Ansatz ist die Verwendung von Flash in ensureAuthenticated

req.flash('redirectTo', req.path)
res.redirect('/login')

Und dann in GET Login

res.render('login', { redirectTo: req.flash('redirectTo') })

In der Ansicht ein verstecktes Feld zum Anmeldeformular hinzufügen (Beispiel in Jade)

if (redirectTo != '')
    input(type="hidden" name="redirectTo" value="#{redirectTo}")

In POST login

res.redirect(req.body.redirectTo || '/')

Beachten Sie, dass redirectTo nach der ersten Anmeldung mit GET gelöscht wird.

1

Der einfachste (und richtigste) Weg, dies zu erreichen, ist Einstellen der Optionen failureRedirect und successRedirect .

1
Eray