Создайте безопасный API oauth с помощью passport.js и express.js (node.js)

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

У меня есть приложение с 2-мя сторонами, клиент (html-сайт) и API (созданный с помощью экспресс + mongodb). К API нужно будет получить безопасный доступ. Они оба находятся в разных доменах, а теперь предположим, что мой сайт находится на domain.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!
});

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

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

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

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

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

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

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

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

2 ответа

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

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

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

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

GET / endpoint / abc123? Access_token = abcdefg

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

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

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

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

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();
 }
});
Другие вопросы по тегам