Facebook-паспорт с JWT

Я использовал Паспорт на моем сервере для аутентификации пользователей. Когда пользователь подписывается локально (используя имя пользователя и пароль), сервер отправляет им JWT, который хранится в localstorage, и отправляется обратно на сервер для каждого вызова api, требующего аутентификации пользователя.

Теперь я хочу поддерживать Facebook и Google login. Поскольку я начал с Passport, я подумал, что лучше продолжить стратегии Passport, используя паспорт-facebook и паспорт-google-oauth.

Я буду ссылаться на Facebook, но обе стратегии ведут себя одинаково. Они оба требуют перенаправления на маршрут сервера ( '/auth/facebook' и '/auth/facebook/callback', если на то пошло). Процесс успешно подходит для сохранения пользователей, включая их facebook\google ids и токены в БД.

Когда пользователь создается на сервере, создается 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, , я получаю токен, но я не перенаправлен на свое приложение.

Любое решение для этого? Является ли мой подход неправильным? Любые предложения сделают.

Ответ 1

Лучшим решением, которое я нашел для этой проблемы, было бы перенаправление на ожидаемую страницу с файлом cookie, который содержит JWT.

Использование 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 более безопасно, и есть еще решения безопасности, которые вы можете использовать, чтобы сделать его еще более безопасным, в отличие от параметра запроса, который явно небезопасен.

Ответ 2

Решение propre предназначено для реализации перенаправления на стороне клиента.

Просто используйте:

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, иначе перенаправляйтесь на страницу входа.