Создайте безопасный API oauth с паспортом. Js и express.js(node.js)

У меня есть определенная проблема, если я не буду делать все правильно.

У меня есть приложение с двумя сторонами, клиентом (html-сайт) и API (построено с помощью express + mongodb). API должен быть надежно защищен. Они оба находятся в разных доменах, а теперь пусть мой сайт находится на домене .com, а мой API находится на api.com:3000.

Я добавил паспорт, чтобы получить токен доступа от Github, поскольку я создаю своих пользователей с их данными, поэтому я могу иметь "Войти с Github" в основном.

Мой текущий процесс:

1) клиент (сайт) открывает всплывающее окно API

window.open("http://api.com:3000/oauth")

2) Экспресс-сервер запустит процесс паспорта:

app.get('/oauth', passport.authenticate('github'), function(req, res) {

});

Для стратегии я использовал этот код.

3) Я перенаправляю обратный вызов на URL-адрес, который закрывает всплывающее окно (javascript с помощью window.close()):

app.get('/oauth/callback', passport.authenticate('github', { failureRedirect: '/' }), function(req, res) {
    res.redirect('/auth_close');
});

В этот момент все в порядке, теперь я зарегистрирован в API. Моя проблема заключается в том, как вернуть данные клиенту, поскольку клиент еще ничего не знает о accessToken, идентификаторе пользователя или пользователя.

Итак, от клиента (сайта, который открывает всплывающее окно), я пробовал разные подходы:

  • Получение значения из всплывающего окна: не работает из-за перенаправления, я теряю информацию о всплывающем javascript

  • вызов моего API для получения текущего пользователя в сеансе, например http://api.com:3000/current Еще одна просьба, а не идеальная, но эта работа. Однако у меня все еще есть проблема.

Этот/текущий url возвращает пользователя, если я его получаю из браузера, потому что браузер отправляет запрос заголовка куки файла экспресс-сессии:

Cookie:connect.sid=s%3AmDrM5MRA34UuNZqiL%2BV7TMv6.Paw6O%2BtnxQRo0vYNKrher026CIAnNsHn4OJdptb8KqE

Проблема в том, что мне нужно сделать этот запрос из jquery или аналогичного, и что там, где он терпит неудачу, потому что сеанс не отправлен. Таким образом, пользователь не возвращается:

app.get('/current', function() {
    // PROBLEM HERE, req.user is undefined with ajax calls because of the session!
});

Я нашел способ заставить его работать, но я не доволен, потому что у меня будут проблемы с CSR-броузерами, они добавляют к выражению:

res.header("Access-Control-Allow-Credentials", "true");

И добавьте поле withCredentials в jQuery ajax-вызове, как описано здесь.

Карта пар fieldName-fieldValue для установки на собственный объект XHR. Например, вы можете использовать его для установки withCredentials в true для междоменных запросов, если это необходимо.

$.ajax({
   url: a_cross_domain_url,
   xhrFields: {
      withCredentials: true
   }
});

Я тоже не доволен этим, поскольку я теряю подстановочный знак в своем заголовке: Access-Control-Allow-Origin, мне нужно указать домен, как описано здесь.

Итак, я не уверен в том, что я должен принять здесь, единственное, что мне нужно, - это клиент, получающий либо accessToken, либо идентификатор пользователя обратно из процесса паспорта. Идея использует этот токен в каждом вызове API для проверки вызовов.

Любая подсказка?

Ответ 1

У меня была такая же проблема. Я использовал локальную стратегию на странице входа в систему, а затем проверил, был ли пользователь включен в сеанс по другим запросам.

Как вы говорите, решение заключается в использовании CORS для того, чтобы идентификатор сеанса передавался в cookie с использованием XMLHTTPRequest.

Вместо того, чтобы использовать CORS, который еще не работает на всех червяках, я обманул использование токенов доступа по другим запросам. Рабочий процесс, который я использовал, выглядит следующим образом:

POST /login
  • Имя пользователя и пароль передаются в теле.
  • Аутентификация с использованием локальной стратегии.
  • Ответ возвращает объект пользователя, включая access_token

GET/endpoint/abc123? access_token = abcdefg

  • Токен, полученный из ответа на вход
  • Аутентификация с использованием стратегии на предъявителя (в паспорт-http-носителе)

Сеансы теперь не нужны в Express.

Я надеюсь, что эта альтернатива поможет.

Ответ 2

Прежде чем настраивать что-либо в экспресс-приложении, используйте следующее (точно такое же), чтобы установить заголовок ответа для междоменного домена:

app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if ('OPTIONS' == req.method) {
     res.send(200);
 } else {
     next();
 }
});