web-dev-qa-db-ja.com

PassportJSがNodeログアウト時にセッションを削除しないのはなぜですか

PassportJSでシステムをログアウトさせるのに問題があります。ログアウトルートが呼び出されているようですが、セッションは削除されていません。ユーザーが特定のルートにログインしていない場合、401を返します。 authenticateUserを呼び出して、ユーザーがログインしているかどうかを確認します。

どうもありがとう!

/******* This in index.js *********/
// setup passport for username & passport authentication
adminToolsSetup.setup(passport);

// admin tool login/logout logic
app.post("/adminTool/login",
    passport.authenticate('local', {
        successRedirect: '/adminTool/index.html',
        failureRedirect: '/',
        failureFlash: false })
);
app.get('/adminTool/logout', adminToolsSetup.authenticateUser, function(req, res){
    console.log("logging out");
    console.log(res.user);
    req.logout();
    res.redirect('/');
});


// ******* This is in adminToolSetup ********
// Setting up user authentication to be using user name and passport as authentication method,
// this function will fetch the user information from the user name, and compare the password     for authentication
exports.setup = function(passport) {
    setupLocalStrategy(passport);
    setupSerialization(passport);
}

function setupLocalStrategy(passport) {
    passport.use(new LocalStrategy(
        function(username, password, done) {
            console.log('validating user login');
            dao.retrieveAdminbyName(username, function(err, user) {
                if (err) { return done(err); }
                if (!user) {
                    return done(null, false, { message: 'Incorrect username.' });
                }
                // has password then compare password
                var hashedPassword = crypto.createHash('md5').update(password).digest("hex");
                if (user.adminPassword != hashedPassword) {
                    console.log('incorrect password');
                    return done(null, false, { message: 'Incorrect password.' });
                }
                console.log('user validated');
                return done(null, user);
            });
        }
    ));
}

function setupSerialization(passport) {
    // serialization
    passport.serializeUser(function(user, done) {
        console.log("serialize user");
        done(null, user.adminId);
    });

    // de-serialization
    passport.deserializeUser(function(id, done) {
        dao.retrieveUserById(id, function(err, user) {
            console.log("de-serialize user");
            done(err, user);
        });
    });
}

// authenticating the user as needed
exports.authenticateUser = function(req, res, next) {
    console.log(req.user);
    if (!req.user) {
        return res.send("401 unauthorized", 401);
    }
    next();
}
64
Jeffrey Chen

ブライスの答えは素晴らしい、しかし、私はまだ重要な区別をすることに気づいた。 Passportガイドは、.logout()(別名.logOut()としても)を使用することを提案しています:

app.get('/logout', function(req, res){
  req.logout();
  res.redirect('/'); //Can fire before session is destroyed?
});

しかし、前述のように、これは信頼できません。 Briceの提案を次のように実装すると、期待どおりに動作することがわかりました。

app.get('/logout', function (req, res){
  req.session.destroy(function (err) {
    res.redirect('/'); //Inside a callback… bulletproof!
  });
});

お役に立てれば!

74
jlmakes

同じ問題に遭遇しました。 req.session.destroy();の代わりにreq.logout();を使用しても機能しますが、これがベストプラクティスかどうかはわかりません。

41
Brice

session.destroyでは不十分な場合があります。ユーザーが完全にログアウトされるようにするには、セッションCookieもクリアする必要があります。

ここでの問題は、アプリケーションが単一ページアプリのAPIとしても使用されている場合(推奨されませんが、非常に一般的)、ログアウト前に開始し、ログアウト後に終了するいくつかのリクエストがExpressによって処理される可能性があることです。この場合、この実行時間の長いリクエストは、削除されたセッションをredisで復元します。また、次回ページを開いたときにブラウザには同じCookieが保持されているため、正常にログインできます。

req.session.destroy(function() {
    res.clearCookie('connect.sid');
    res.redirect('/');
});

そうでない場合は、次のようになります。

  1. 要求1(要求)が受信された
  2. Req 1はセッションをredisからメモリにロードします
  3. ログアウトリクエストを受信しました
  4. ログアウト要求はセッションをロードします
  5. ログアウトリクエストによりセッションが破棄される
  6. ログアウトリクエストはブラウザにリダイレクトを送信します(Cookieは削除されません)
  7. Req 1は処理を完了します
  8. Req 1はセッションをメモリからredisに保存します
  9. Cookieとセッションの両方が設定されているため、ユーザーはログインダイアログなしでページを開きます。

理想的には、API呼び出しにトークン認証を使用し、ページのみをロードするWebアプリのセッションのみを使用する必要がありますが、WebアプリがAPIトークンの取得にのみ使用される場合でも、この競合状態は依然として可能です。

10
esp

私は同じ問題を抱えていましたが、Passport関数の問題ではなく、_/logout_ルートを呼び出す方法で問題であることが判明しました。フェッチを使用してルートを呼び出しました:

(悪い)

_fetch('/auth/logout')
  .then([other stuff]);
_

クッキーを送信しないことでセッションが継続されず、res.logout()が別のセッションに適用されると思いますか?とにかく、次の操作を行うことで修正できます。

(良い)

_fetch('/auth/logout', { credentials: 'same-Origin' })
  .then([other stuff]);
_
7
nrflaw

私は同じ問題を抱えていました、資本Oはそれを修正しました。

app.get('/logout', function (req, res){
  req.logOut()  // <-- not req.logout();
  res.redirect('/')
});

編集:これはもはや問題ではありません。

5
abitofcode

私は最近この同じ問題を抱えていましたが、答えはどれも私のために問題を解決しませんでした。間違っている可能性がありますが、競合状態に関係しているようです。

セッションの詳細を以下のオプションに変更すると、問題が修正されたようです。私はそれを約10回テストしましたが、すべてが正常に機能しているようです。

_app.use(session({
    secret: 'secret',
    saveUninitialized: false,
    resave: false
}));
_

基本的に、saveUninitializedresavetrueからfalseに変更しました。これで問題が修正されたようです。

参考のために、ログアウトパスで標準のreq.logout();メソッドを使用しています。私は他の人が言ったようにセッションdestroyを使用していません。

_app.get('/logout', function(req, res) {
    req.logout();
    res.redirect('/');
});
_
4
Charlie Fish

req.logout()req.session.destroy()の両方を使用し、正常に動作します。

server.get('/logout', (req, res) => {
  req.logout();
  req.session.destroy();
  res.redirect('/');
});

言うまでもなく、セッションストアとしてRedisを使用します。

4
sstauross

自分でセッションを破棄するのは奇妙に見えます。次の構成を持つこの問題に直面しました:

_"express": "^4.12.3",
"passport": "^0.2.1",
"passport-local": "^1.0.0",
_

私はこの構成うまくいくと言うべきです。私の問題の理由は、ここで定義したカスタムsessionStoreにありました。

_app.use(expressSession({
    ...
    store: dbSessionStore,
    ...
}));
_

ここでもあなたの問題を確実にするには、ストア行をコメント化し、セッションを維持せずに実行してください。動作する場合は、カスタムセッションストアを調べてください。私の場合、setメソッドの定義が間違っていました。 req.logout() session store destroy()メソッドを使用すると、以前考えたように呼び出されません。代わりに、更新されたセッションでsetメソッドを呼び出しました。

幸運を祈ります。この回答がお役に立てば幸いです。

1
DontRelaX

パスポートを適切にセットアップできなかったために動作しない場合がありました。たとえば、vhostを実行しますが、メインアプリではパスポートをこのように設定しますが、これは間違っています。

app.js(なぜ間違っていますか?以下のblockqouteをご覧ください)

_require('./modules/middleware.bodyparser')(app);
require('./modules/middleware.passport')(app);
require('./modules/middleware.session')(app);
require('./modules/app.config.default.js')(app, express);

// default router across domain
app.use('/login', require('./controllers/loginController'));
app.get('/logout', function (req, res) {
    req.logout();
    res.redirect('/');
});

// vhost setup
app.use(vhost('sub1.somehost.dev', require('./app.Host.sub1.js')));
app.use(vhost('somehost.dev', require('./app.Host.main.js')));
_

実際には、ログインできないようにする必要がありますが、私はそれを管理することができます。ここに別のパスポート設定を置くことにより、セッションフォーム_app.js_が_app.Host.sub1.js_で利用可能になります

app.Host.sub1.js

_// default app configuration
require('./modules/middleware.passport')(app);
require('./modules/app.config.default.js')(app, express);
_

だから、ログアウトしたいときは... _app.js_は_passport.js_の前に_express-session.js_を初期化することで何か間違ったことをしていたので、うまくいきません!.

ただし、他の人が言及しているように、このコードはとにかく問題を解決できます。

app.js

_app.get('/logout', function (req, res) {
    req.logout();
    req.session.destroy(function (err) {
        if (err) {
            return next(err);
        }

        // destroy session data
        req.session = null;

        // redirect to homepage
        res.redirect('/');
    });
});
_

しかし、私の場合は正しい方法です...express-session.jspassport.jsの前に交換します

ドキュメント も言及

セッションサポートの有効化は完全にオプションですが、ほとんどのアプリケーションで推奨されています。有効にした場合は、passport.session()の前にexpress.session()を使用して、ログインセッションが正しい順序で復元されるようにしてください。

それで、私の場合のログアウトの問題を解決しました。

app.js

_require('./modules/middleware.bodyparser')(app);
require('./modules/middleware.session')(app);
require('./modules/middleware.passport')(app);
require('./modules/app.config.default.js')(app, express);


// default router across domain
app.use('/login', require('./controllers/loginController'));
app.get('/logout', function (req, res) {
    req.logout();
    res.redirect('/');
});
_

app.Host.sub1.js

_// default app configuration
require('./modules/app.config.default.js')(app, express);
_

そして今、req.logout();が動作するようになりました。

1
Jongz Puangput

答えはどれも役に立たなかったので、共有します

app.use(session({
    secret: 'some_secret',
    resave: false,
    saveUninitialized: false,
   cookie: {maxAge: 1000} // this is the key
}))

そして

router.get('/logout', (req, res, next) => {
    req.logOut()
    req.redirect('/')
})
1
user1733031

私は同じ問題を抱えていました。私のバージョンのパスポートはExpress 4.0と互換性がないことが判明しました。古いバージョンをインストールするだけです。

    npm install --save [email protected]
0
Ryan

これは私のために働いた:

app.get('/user', restrictRoute, function (req, res) {
  res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate,
              max-stale=0, post-check=0, pre-check=0');
});

ページがキャッシュに保存されないようにします

0

ここのすべての例は、req.session.destroyの後にリダイレクトを行います。ただし、リダイレクト先のページに対してExpressが新しいセッションを即座に作成することを理解してください。 Postmanとの組み合わせで、ログアウトの直後にPassport-Loginを実行するとPassportは成功するが、ユーザーIDをセッションファイルに保存できないという奇妙な動作を発見しました。その理由は、PostmanはこのグループのすべてのリクエストでCookieを更新する必要があり、これには時間がかかるためです。また、破壊のコールバックでのリダイレクトは役に立ちません。

リダイレクトを行わず、jsonメッセージを返すだけで解決しました。

0
BertC

どうやらこの問題の原因は複数考えられます。私の場合、問題は間違った宣言の順序でした。つまり、パスポートの初期化の前にログアウトエンドポイントが宣言されました。正しい順序は次のとおりです。

app.use(passport.initialize());
app.use(passport.session());


app.get('/logout', function(req, res) {
  req.logout();
  res.redirect('/');
});
0

ブラウザでセッションを破棄するには、req.logout()を使用する必要があります。

app.get('/logout', function(req, res) {
    req.logout();
    res.redirect('/'); // whatever the route to your default page is
});
0
Anuj Kumar

Reqのユーザーを削除することを提案するプログラマーと作業しています。

app.get('/logout', function (req, res){
  req.session.destroy(function (err) {
    req.user = null;
    res.redirect('/'); //Inside a callback… bulletproof!
  });
});

理由: req(passportjsもこれを行うが、非同期の方法)から削除する必要がある新しいセッションとリダイレクト(まだ行われていません)ところで、これは無関係なものを削除する責任です。 PassportJSはログイン後にreq.userにデータを割り当て、req.logout()を使用する場合は削除しますが、NodeJS非同期としての性質上、正常に動作しない場合があります

0
mrmccormack

Passport 0.3.2でも同様の問題に直面しました。

パスポートログインとサインアップにカスタムコールバックを使用すると、問題が解決しませんでした。

この問題は、Passport 0.4.0にアップグレードして行を追加することで解決しました

app.get('/logout', function(req, res) {
    req.logOut();
    res.redirect('/');
});
0
Venu

connect.sid Cookieを介して独自のセッションを使用するパスポート認証を使用しているため、ログアウトを処理するこの最も簡単な方法は、パスポートにセッションを処理させることです。

app.get('/logout', function(req, res){
  if (req.isAuthenticated()) {
    req.logOut()
    return res.redirect('/') // Handle valid logout
  }

  return res.status(401) // Handle unauthenticated response
})
0
acharlop