web-dev-qa-db-ja.com

パスポートのログインと永続的なセッション

バックグラウンド

私は郵便配達員で完全にテストされたCRUD機能を備えたMEANアプリケーションを持っています。幸運なことに今しばらくログインを維持しようとしています。私は以下を読んで試しました

しかし、セッションでのログインを保持するのではなく、ユーザーを登録してログインすることしかできませんでした。

私のアプリ

ここ は完全なgithubリポジトリへのリンクです(最新の変更を確認する場合は、developブランチを確認してください)

認証/ログインの私の理解

以下は、プロジェクトのコード例と、ポストマンの結果のスクリーンショット、およびコンソールログを使用したユーザーログインの理解です。

パスポートのセットアップ

私は次のauth.jsファイルを持っています、それはパスポートを設定します

_var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

module.exports = function(app, user){

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

  // passport config
  passport.use(new LocalStrategy(user.authenticate()));

  passport.serializeUser(function(user, done) {
    console.log('serializing user: ');
    console.log(user);
    done(null, user._id);
  });

  passport.deserializeUser(function(id, done) {
    user.findById(id, function(err, user) {
      console.log('no im not serial');
      done(err, user);
    });
  });
};
_

これは、次のようなサーバーファイルで呼び出されます

_//code before
var user    = require('./models/user.js');
var auth    = require('./modules/auth.js')(app, user);
// code after
_

ログインのルーティング

私のルートには、次のようなログインルートがあります

_router.post('/login', function(req, res, next) {

  passport.authenticate('local', function(err, user, info) {

    if (err) {
        return next(err);
    }

    if (!user) {
        return res.status(401).json({
            err: info
        });
    }

    req.logIn(user, function(err) {

        if (err) {
            return res.status(500).json({
                err: 'Could not log in user'
            });
        }

        res.status(200).json({
            status: 'Login successful!'
        });

    });
  })(req, res, next);
});
_

このルートworksはpostmanでテストされています。 「joe」と「pass」の詳細を入力すると、次の応答が返されます。

enter image description here

このルートがヒットすると、ユーザーがシリアル化されていることもコンソールで確認できます。

enter image description here

それでは、次は何ですか?

これは私が迷子になる場所です。少し質問があります。

  1. ユーザーは現在サーバー上のセッションにいますか?
  2. _req.session.passport.user_をクライアントに返すべきですか?
  3. 今後のすべてのリクエストでセッションIDが必要ですか?

セッションのテスト

セッションをテストするための2番目のルート設定があります。次のとおりです。

_router.get('/checkauth', passport.authenticate('local'), function(req, res){

    res.status(200).json({
        status: 'Login successful!'
    });

});
_

ルートにアクセスする前にユーザーセッションが存在するかどうかをテストするためにpassport.authenticate('local')の部分がありますが、これを実行してもログイン後でも200の応答が返されません。

このルートは、_req.session.passport.user_がヘッドで渡されるか、または認証を必要とするhttp要求のデータ引数として渡されることを期待していますか?

私が何かを見逃したか、何か間違ったことを理解している場合は教えてください、入力は大歓迎です。皆さんありがとう。

33
Joe Lloyd

ユーザーは現在サーバー上のセッションにいますか?

いいえ、セッションを実際にメモリ/データベースに保存するには、app.use(passport.session());の前に_express-session_ミドルウェアを使用する必要があります。このミドルウェアは、ブラウザーにCookieを設定し、ブラウザーから送信されたCookieを_req.session_オブジェクトに変換します。 PassportJSは、そのオブジェクトを使用して、ユーザーをさらに逆シリアル化します。

req.session.passport.userをクライアントに返送しますか?

クライアントがログイン時にuserリソースを期待している場合は、そうする必要があります。それ以外の場合、ユーザーオブジェクトをクライアントに送信する理由はありません。

今後のすべてのリクエストでセッションIDが必要ですか?

はい、今後のすべてのリクエストには、セッションIDが必要です。ただし、クライアントがブラウザの場合、何も送信する必要はありません。ブラウザはセッションIDをCookieとして保存し、Cookieの有効期限が切れるまで、以降のすべてのリクエストに対してセッションIDを送信します。 _express-session_はそのCookieを読み取り、対応するセッションオブジェクトを_req.session_としてアタッチします。

セッションのテスト

passport.authenticate('local')は、POST body。からのユーザー資格情報を認証するためのものです。ログインルートにのみ使用する必要があります。

ただし、ユーザーが他のすべてのルートで認証されているかどうかを確認するには、_req.user_が定義されているかどうかを確認できます。

_function isAuthenticated = function(req,res,next){
   if(req.user)
      return next();
   else
      return res.status(401).json({
        error: 'User not authenticated'
      })

}
router.get('/checkauth', isAuthenticated, function(req, res){

    res.status(200).json({
        status: 'Login successful!'
    });
});
_
61
hassansin

@hassansinが言うように、セッション管理を実装するミドルウェアを使用する必要があります。 passport.session()ミドルウェアは、パスポートフレームワークをセッション管理に接続し、セッション自体を実装しません。 express-sessionミドルウェア セッション管理を実装します。次の方法でauth.jsを変更する必要があります

var passport = require('passport');
var session = require('express-session');
var LocalStrategy = require('passport-local').Strategy;

module.exports = function(app, user){
  app.use(session({secret: 'some secret value, changeme'}));    

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

  // passport config
  passport.use(new LocalStrategy(user.authenticate()));

  passport.serializeUser(function(user, done) {
    console.log('serializing user: ');
    console.log(user);
    done(null, user._id);
  });

  passport.deserializeUser(function(id, done) {
    user.findById(id, function(err, user) {
      console.log('no im not serial');
      done(err, user);
    });
  });
};

この場合、セッションエンジンはメモリ内ストアを使用しており、アプリケーションをスケーリングして負荷分散を適用すると機能しなかったことに注意してください。この開発状態に到達すると、 connect-redisセッションストア が必要になります。

また、セッションミドルウェアコールで使用されるシークレット値を変更し、すべてのアプリケーションインスタンスで同じ値を使用する必要があることに注意してください。

12
yeiniel

パスポートのドキュメントreq.userは認証されたユーザーに設定されます。ただし、これを機能させるには、express-sessionモジュール。パスポートが機能するためにすでに持っているもの以外に何も必要ないはずです。

セッションをテストする限り、req.userが設定されているかどうかを確認するミドルウェア機能を使用できます。設定されている場合はユーザーが認証されていることがわかり、設定されていない場合はユーザーをリダイレクトできます。

たとえば、認証する任意のルートで使用できるミドルウェア機能を使用できます。

authenticated.js

module.exports = function (req, res, next) {
    // if user is authenticated in the session, carry on
    if (req.user) {
        next();
    }
    // if they aren't redirect them to the login page
    else {
        res.redirect('/login');
    }
};

コントローラー

var authenticated = require('./authenticated');

router.get('/protectedpage', authenticated, function(req, res, next) {
    //Do something here
});
2

Passport.jsは、セッションをサーバーに保存するためうまく機能しません(不良でスケーラブルではありません)。サーバーにセッションデータを格納する(ステートレスのままにする)ことは望ましくありません。クラスターをスケールアップし、より多くのリクエストを処理できるからです。

Passport.jsライブラリのコードを見ると、それほど多くはありません。実際に自分でビルドすると、より高速で効率的になります。

Googleにもっと良い方法で接続することについて書いたチュートリアル です。

0
Jack

既存のすべてのセッションを確認する方法はわかりませんが、PassportはセッションIDの発行を処理しています。ログイン後にテストエンドポイントにreq.userがあることを確認してください

0
tcmoore