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>
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);
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;
});
Schauen Sie sich connect-verify-login an, das neben Passport funktioniert, um genau das zu tun, was Sie wollen!
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
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:
@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.
Der einfachste (und richtigste) Weg, dies zu erreichen, ist Einstellen der Optionen failureRedirect
und successRedirect
.