web-dev-qa-db-ja.com

JWTを使用したFacebookパスポート

サーバーでユーザー認証にPassportを使用しています。ユーザーがローカルでサインインしているとき(ユーザー名とパスワードを使用)、サーバーはローカルストレージに保存されている[〜#〜] jwt [〜#〜]を送信し、サーバーに送信されます。ユーザー認証を必要とするすべてのAPI呼び出し。

今、私はFacebookおよびGoogleログインもサポートしたいと考えています。 Passportを使い始めて以来、passport-facebookpassport-google-oauthを使用してPassport戦略を続行するのが最善だと思いました。

私はFacebookについて言及しますが、どちらの戦略も同じように動作します。どちらもサーバールートへのリダイレクトが必要です('/ auth/facebook'および'/ auth/facebook/callback'についても)。このプロセスは成功し、facebook\google IDとトークンを含むユーザーをDBに保存します。

ユーザーがサーバー上で作成されると、JWTが作成されます(facebook\googleから受信したトークンに依存しません)。

     ... // Passport facebook startegy
     var newUser = new User();
     newUser.facebook = {};
     newUser.facebook.id = profile.id; 
     newUser.facebook.token = token; // token received from facebook
     newUser.facebook.name  = profile.displayName;   
     newUser.save(function(err) {
          if (err)
               throw err;
          // if successful, return the new user
          newUser.jwtoken = newUser.generateJwt(); // JWT CREATION!
          return done(null, newUser);
     });

問題は、作成後にJWTをクライアントに送信する適切な方法が見つからないです。これは、アプリにもリダイレクトする必要があるためです。

app.get('/auth/facebook/callback',
    passport.authenticate('facebook', {
        session: false,
        successRedirect : '/',
        failureRedirect : '/'
    }), (req, res) => {
        var token = req.user.jwtoken;
        res.json({token: token});
    });

上記のコードアプリのメインページにリダイレクトされますが、トークンを取得できません。 successRedirectを削除すると、トークンは取得されますが、アプリにリダイレクトされません

そのための解決策はありますか?私のアプローチは間違っていますか?提案があれば十分です。

24
Bar Kedem

その問題に対して私が見つけた最良の解決策は、JWTを保持するCookieを使用して予期されたページにリダイレクトすることです。

res.jsonを使用すると、json応答のみが送信され、リダイレクトされません。これが、ここで提案されている他の回答では、私が遭遇した問題を解決できない理由です。

だから私の解決策は:

app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
    session: false,
    successRedirect : '/',
    failureRedirect : '/'
}), (req, res) => {
    var token = req.user.jwtoken;
    res.cookie('auth', token); // Choose whatever name you'd like for that cookie, 
    res.redirect('http://localhost:3000'); // OR whatever page you want to redirect to with that cookie
});

リダイレクト後、Cookieを安全に読み取り、期待どおりにそのJWTを使用できます。 (実際に、ページが読み込まれるたびにCookieを読み取って、ユーザーがログインしているかどうかを確認できます)

前に述べたように、クエリパラメータとしてJWTを使用してリダイレクトすることは可能ですが、非常に安全ではありません。 Cookieを使用する方が安全であり、明らかに安全ではないクエリパラメータとは異なり、Cookieをさらに安全にするために使用できるセキュリティソリューションがまだあります。

11
Bar Kedem

バーの答えに追加します。

Cookieを抽出してローカルストレージに保存し、Cookieを削除して、承認済みページにリダイレクトするランディングコンポーネントを準備しました。

class SocialAuthRedirect extends Component {
  componentWillMount() {
    this.props.dispatch(
      fbAuthUser(getCookie("auth"), () => {
        document.cookie =
          "auth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
        this.props.history.Push("/profile");
      })
    );
  }

  render() {
    return <div />;
  }
}
3
Tetsuya3850

適切な解決策は、クライアント側でリダイレクトを実装することです。

単に使用:

app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
    session: false,
    failureRedirect: '/login'
  }), (req, res) => {
    res.json({
      token: req.user.jwtoken
    })
  }
)

クライアント側がトークンを受信し、そこからホームページにリダイレクトする場合、ログインが成功しなかった場合は、サーバーによって直接リダイレクトされます。

または、私がするように完全なクライアント側管理に行くことができます:

app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
    session: false
  }), (req, res) => {
    if (req.user.jwtoken) {
      res.json({
        success: true,
        token: req.user.jwtoken
      })
    } else {
      res.json({
        success: false
      })
    }
  }
)

success === true、JWTをLocalStorageに保存します。それ以外の場合は、ログインページにリダイレクトします。

1
SherloxFR