Перенаправление на предыдущую страницу после аутентификации в node.js с использованием файла passport.js
Я пытаюсь установить механизм входа, используя node.js, express и passport.js. Сам вход работает очень хорошо, также сеансы хорошо сохраняются с redis, но у меня есть некоторые проблемы с перенаправлением пользователя туда, откуда он начал, перед тем как будет предложено пройти аутентификацию.
например. Пользователь, следующий за ссылкой http://localhost:3000/hidden
, затем перенаправляется на http://localhost:3000/login
, но затем я хочу, чтобы он снова перенаправлялся на http://localhost:3000/hidden
.
Целью этого является то, что если пользователь случайно получает страницу, которую он должен сначала регистрировать, он должен быть перенаправлен на сайт /login, предоставляющий свои учетные данные, а затем перенаправляется обратно на сайт, к которому он ранее пытался получить доступ.
Вот мой вход в систему
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);
});
и здесь мой secureAuthenticated Method
function ensureAuthenticated (req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
}
который перехватывает страницу /hidden
app.get('/hidden', ensureAuthenticated, function(req, res){
res.render('hidden', { title: 'hidden page' });
});
Выход html для входа в систему довольно прост
<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>
Ответы
Ответ 1
Я не знаю о паспорте, но вот как я это делаю:
У меня есть промежуточное ПО, которое я использую с app.get('/account', auth.restrict, routes.account)
, которое устанавливает redirectTo
в сеансе... затем я перенаправляю /login
auth.restrict = function(req, res, next){
if (!req.session.userid) {
req.session.redirectTo = '/account';
res.redirect('/login');
} else {
next();
}
};
Тогда в routes.login.post
я делаю следующее:
var redirectTo = req.session.redirectTo ? req.session.redirectTo : '/';
delete req.session.redirectTo;
// is authenticated ?
res.redirect(redirectTo);
Ответ 2
В вашем методе ensureAuthenticated
сохраните возвращаемый url в сеансе следующим образом:
...
req.session.returnTo = req.path;
res.redirect('/login');
...
Затем вы можете обновить свой паспорт. Проверить подлинность маршрута на что-то вроде:
app.get('/auth/google/return', passport.authenticate('google'), function(req, res) {
res.redirect(req.session.returnTo || '/');
delete req.session.returnTo;
});
Ответ 3
Взгляните на connect-ensure-login, который работает вместе с паспортом, чтобы сделать именно то, что вы хотите!
Ответ 4
Если вы используете connect-ensure-login, это очень простой и интегрированный способ сделать это с помощью Passport с помощью параметра successReturnToOrRedirect
. При использовании паспорт отправит вас обратно на первоначально запрошенный URL-адрес или вернется к указанному вами URL-адресу.
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
Мой способ делать вещи:
const isAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return next()
}
res.redirect( `/login?origin=${req.originalUrl}` )
};
Контроллер GET/login:
if( req.query.origin )
req.session.returnTo = req.query.origin
else
req.session.returnTo = req.header('Referer')
res.render('account/login')
Контроллер POST/login:
let returnTo = '/'
if (req.session.returnTo) {
returnTo = req.session.returnTo
delete req.session.returnTo
}
res.redirect(returnTo);
Контроллер POST/logout (не уверен, что есть 100% нормально, комментарии приветствуются):
req.logout();
res.redirect(req.header('Referer') || '/');
if (req.session.returnTo) {
delete req.session.returnTo
}
Clear returnTo middleware (очищает returnTo от сеанса на любом маршруте, кроме auth-маршрутов - для меня они /login и/auth/: поставщик):
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()
})
Этот подход имеет две функции:
- вы можете защитить некоторые маршруты с помощью промежуточного программного обеспечения isAuthenticated;
- на любой странице вы можете просто щелкнуть по URL-адресу входа и после входа в систему на этой странице;
Ответ 6
В ответах @chovy и @linuxdan есть ошибка, не очищая session.returnTo
, если пользователь переходит на другую страницу после переадресации входа (это не требует аутентификации) и входа в систему. Поэтому добавьте этот код в свои реализации:
// 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()
})
Если вы выполните некоторые запросы ajax со страницы входа, вы также можете их исключить.
Другим подходом является использование flash в ensureAuthenticated
req.flash('redirectTo', req.path)
res.redirect('/login')
И затем в GET login
res.render('login', { redirectTo: req.flash('redirectTo') })
В поле "Добавить скрытое поле" введите форму входа (пример в нефрит)
if (redirectTo != '')
input(type="hidden" name="redirectTo" value="#{redirectTo}")
В поле входа в систему
res.redirect(req.body.redirectTo || '/')
Обратите внимание, что redirectTo будет очищаться после первого входа в систему с его именем.
Ответ 7
Самый простой (и правильно) способ достичь этого - настройка failureRedirect
и successRedirect
параметров.