web-dev-qa-db-ja.com

NodejsおよびPassportJs:認証が失敗した場合にpassport.authenticateが呼び出されない場合にミドルウェアをリダイレクトします

ログインページはありませんが、すべてのページに表示されるログインフォームがあります。認証が成功したかどうかに関係なく、ユーザーをリダイレクト先の同じページにリダイレクトしたい(適切なフラッシュメッセージを使用)

次のコードを見てください。

app.post('/login', validateLogin, passport.authenticate('local-login'), function(req, res) {

    var redirectUrl = '/'; 

    if(req.body.to.length > 0){
        redirectUrl = req.body.to;  
    }

    console.log("THIS IS ONLY CALLED IF passport.authenticate() IS SUCCESSFUL");
    res.redirect(redirectUrl);
});

上記の最後のミドルウェアが呼び出されるのは、認証に合格した場合のみです。失敗した場合、パスポートがgetリクエストの形式で/ loginにリダイレクトしているようです。私のアプリでは、このページは存在しません。

追加のオプションオブジェクトをパスポート認証関数のパラメーターとして渡すと、次のように機能します。

app.post('/login', validateLogin, passport.authenticate('local-login', {

successRedirect : '/', // redirect to the secure profile section
    failureRedirect : '/signup', // redirect back to the signup page. THIS IS JUST FOR TESTING TO SEE IF THE REDIRECT ON FAIL WORKS.
    failureFlash : true, // allow flash messages

}


));

しかし、これを行うと、ユーザーをリダイレクトする場所を選択できなくなります。認証が失敗した場合、パスポートがユーザーのリダイレクト先を制御するようです。どうすれば修正できますか?それともバグですか?認証が失敗した場合、パスポート認証はチェーンの最後のミドルウェアでなければなりませんか?

これは私のローカル戦略関数呼び出しです:

//LOCAL LOGIN

passport.use('local-login', new LocalStrategy({ 
    // by default, local strategy uses username and password, we will override with email
    usernameField : 'email',
    passwordField : 'password',
    passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form


    console.log("IN PASSPORT");

   if(email.length == 0 || password.length == 0){

       console.log("FIELDS ARE EMPTY"); 
      return done(null, false, req.flash('loginMessage', 'Fill in all values.'));

   }

    // find a user whose email is the same as the forms email
    // we are checking to see if the user trying to login already exists
    User.findOne({ 'local.email' :  email }, function(err, user) {
        // if there are any errors, return the error before anything else



        if (err){
            return done(err);
        console.log("db err");
        }
        // if no user is found, return the message
        if (!user){
            console.log("not user");
            return done(null, false, req.flash('loginMessage', 'Incorrect details.')); // req.flash is the way to set flashdata using connect-flash
        }    
        // if the user is found but the password is wrong

        if (!user.validPassword(password)){
            console.log("invalid pw");
            return done(null, false, req.flash('loginMessage', 'Incorrect details.')); // create the loginMessage and save it to session as flashdata
        }    
        // all is well, return successful user
        console.log("All OK");
        return done(null, user);
    });

}));
13
Paulie

そこの最後の段落で説明されているように、カスタム認証コールバックを使用できます http://passportjs.org/guide/authenticate/

app.post('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) { return next(err); }
    // Redirect if it fails
    if (!user) { return res.redirect('/login'); }
    req.logIn(user, function(err) {
      if (err) { return next(err); }
      // Redirect if it succeeds
      return res.redirect('/users/' + user.username);
    });
  })(req, res, next);
});
31
ploutch

成功したFacebook Authに続くリダイレ​​クト呼び出しと同じ問題に遭遇しました

  • passport.authenticate( 'facebook'、..)

..尊敬されていませんでした。

「ローカル」のpassportJS戦略に基づいており、そのことを @ ploutchの回答はこちら ..から通知しています。これを機能させるための鍵は、次の呼び出しにあるようです。

req.logIn(user, function(err) {
 ...
}

Facebookの場合、このルート設定は私にとってうまくいきました:

app.get(
        '/auth/facebook/callback',

        passport.authenticate
        (
            'facebook', 
            { failureRedirect: '/fbFailed' }
        ),

        function(req, res) 
        {
            var user = myGetUserFunc(); // Get user object from DB or etc

            req.logIn(user, function(err) {

              if (err) { 
                req.flash('error', 'SOMETHING BAD HAPPEND');
                return res.redirect('/login');
              }

              req.session.user = user;

              // Redirect if it succeeds
              req.flash('success', 'Fb Auth successful');
              return res.redirect('/user/home');
            });      
        }
); 
3
Gene Bo

これは、提案されたすべてのオプションを試してもうまくいかなかった私のような一部の人々にとって、まだ問題である可能性があることを知っています。

私の場合、結局のところ、req.bodyオブジェクトが常に空であるため、エラーが発生していました。ボディ解析ミドルウェアを正しくセットアップしていたので、なぜこれが起こっているのか理解できませんでした。

さらに調査した結果、フォーム(multipart/form-data)に使用していたenctypeがbody-parserでサポートされていないことがわかりました。別のミドルウェアに切り替えた後、 read me を参照してください。モルター、すべてがスムーズに動作しました。

0
Morrey Davidson

以下を含む完全な回答:

  • RedirectUrlを設定するミドルウェア
  • フラッシュメッセージ
  • 使用されない値を返さない

redirectToミドルウェアにloginRequired値を作成するだけです。

var loginRequired = function(req, res, next) {
    if ( req.isAuthenticated() ) {
        next();
        return
    }
    // Redirect here if logged in successfully
    req.session.redirectTo = req.path;
    res.redirect('/login')
}

そして、あなたのログインPOSTで:

router.post('/login', function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
        if ( err ) {
            next(err);
            return
        }
        // User does not exist
        if ( ! user ) {
            req.flash('error', 'Invalid email or password');
            res.redirect('/login');
            return
        }
        req.logIn(user, function(err) {
            // Invalid password
            if ( err ) {
                req.flash('error', 'Invalid email or password');
                next(err);
                return
            }
            res.redirect(req.session.redirectTo || '/orders');
            return
        });
    })(req, res, next);
});
0
mikemaccana