Создайте безопасный 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();
}
});