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);
});
そして、ここで私のensureAuthenticatedメソッド
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>
私はパスポートについては知りませんが、ここに私がそれをする方法があります:
セッションでredirectTo
を設定するapp.get('/account', auth.restrict, routes.account)
で使用するミドルウェアがあります...その後、/ 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 || '/';
delete req.session.redirectTo;
// is authenticated ?
res.redirect(redirectTo);
ensureAuthenticated
メソッドで、セッションの戻りURLを次のように保存します。
...
req.session.returnTo = req.originalUrl;
res.redirect('/login');
...
次に、passport.authenticateルートを次のようなものに更新できます。
app.get('/auth/google/return', passport.authenticate('google'), function(req, res) {
res.redirect(req.session.returnTo || '/');
delete req.session.returnTo;
});
connect-ensure-login を見てください。これはPassportと共に動作して、まさにあなたが望むことをします!
connect-ensure-login を使用している場合、successReturnToOrRedirect
パラメーターを使用してPassportでこれを行う非常に簡単で統合された方法があります。パスポートを使用すると、最初にリクエストされた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
私のやり方:
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 controller(100%OKかどうかわからない、コメントを歓迎します):
req.logout();
res.redirect(req.header('Referer') || '/');
if (req.session.returnTo) {
delete req.session.returnTo
}
returnToミドルウェアのクリア(authルート以外のルート上のセッションからreturnToをクリアします-私にとっては/ loginと/ 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()
})
このアプローチには2つの機能があります。
@chovyと@linuxdanの回答にはbugがあり、ユーザーがログインリダイレクト(認証を必要としない)して別のページに移動し、そこからログインすると、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リクエストを行う場合、それらを除外することもできます。
別のアプローチは、ensureAuthenticated
でflashを使用することです
req.flash('redirectTo', req.path)
res.redirect('/login')
そして、GETログインで
res.render('login', { redirectTo: req.flash('redirectTo') })
ビューで非表示フィールドをログインフォームに追加します(jadeの例)
if (redirectTo != '')
input(type="hidden" name="redirectTo" value="#{redirectTo}")
POSTログイン
res.redirect(req.body.redirectTo || '/')
最初にGETログインすると、redirectToがクリアされることに注意してください。
これを実現する最も簡単な(そして適切な)方法は failureRedirect
およびsuccessRedirect
オプションを設定する です。