Здесь задается много вопросов, и кажется, что хотя вопросы задаются в контексте Node и passport.js, реальные вопросы больше касаются рабочего процесса, чем того, как это сделать с определенной технологией.
Давайте использовать пример настройки @Keith, немного измененный для дополнительной безопасности:
- Веб-сервер
https://example.com
обслуживает одностраничное клиентское приложение Javascript
- Веб-сервис RESTful at
https://example.com/api
предоставляет поддержку сервера для многофункционального клиентского приложения.
- Сервер реализован в Node и passport.js.
- Сервер имеет базу данных (любого рода) с таблицей «пользователи».
- Имя пользователя / пароль и Facebook Connect предлагаются в качестве параметров аутентификации
- Богатый клиент делает запросы REST в
https://example.com/api
- Могут быть другие клиенты (например, телефонные приложения), которые используют веб-службу,
https://example.com/api
но не знают о веб-сервере в https://example.com
.
Обратите внимание, что я использую безопасный HTTP. По моему мнению, это необходимо для любой службы, доступной в открытом доступе, поскольку конфиденциальная информация, такая как пароли и токены авторизации, передается между клиентом и сервером.
Имя пользователя / пароль аутентификация
Давайте посмотрим, как работает простая старая аутентификация.
- Пользователь подключается к
https://example.com
- Сервер обслуживает богатое приложение Javascript, которое отображает начальную страницу. Где-то на странице есть форма авторизации.
- Многие разделы этого одностраничного приложения не были заполнены данными из-за того, что пользователь не вошел в систему. Во всех этих разделах имеется прослушиватель событий для события «login». Все это на стороне клиента, сервер не знает об этих событиях.
- Пользователь вводит свой логин и пароль и нажимает кнопку отправки, которая запускает обработчик Javascript для записи имени пользователя и пароля в переменных на стороне клиента. Затем этот обработчик запускает событие входа в систему. Опять же, это все действия на стороне клиента, учетные данные еще не отправлены на сервер .
- Слушатели события "login" вызываются. Теперь каждому из них необходимо отправить один или несколько запросов в API RESTful at
https://example.com/api
для получения пользовательских данных, отображаемых на странице. Каждый отдельный запрос, отправляемый веб-службе, будет включать имя пользователя и пароль, возможно, в форме базовой аутентификации HTTP , поскольку службе, имеющей RESTful, не разрешено поддерживать состояние клиента от одного запроса к следующему. Поскольку веб-служба работает по безопасному HTTP, пароль безопасно шифруется во время транзита.
- Веб-сервис
https://example.com/api
получает несколько отдельных запросов, каждый из которых содержит информацию для аутентификации. Имя пользователя и пароль в каждом запросе сверяются с базой данных пользователей, и если они найдены правильно, запрошенная функция выполняется и данные возвращаются клиенту в формате JSON. Если имя пользователя и пароль не совпадают, клиенту отправляется ошибка в виде кода ошибки 401 HTTP.
- Вместо того, чтобы заставлять клиентов отправлять имя пользователя и пароль при каждом запросе, у вас может быть функция «get_access_token» в вашей службе RESTful, которая принимает имя пользователя и пароль и отвечает токеном, который является своего рода криптографическим хешем, который уникален и имеет некоторый срок действия. дата, связанная с этим. Эти токены хранятся в базе данных с каждым пользователем. Затем клиент отправляет токен доступа в последующих запросах. Токен доступа будет затем проверен по базе данных вместо имени пользователя и пароля.
- Клиентские приложения, не являющиеся браузерами, такие как телефонные приложения, выполняют те же действия, что и выше, они просят пользователя ввести свои учетные данные, а затем отправлять их (или сгенерированный из них токен доступа) при каждом запросе к веб-службе.
В этом примере важно отметить, что веб-сервисы RESTful требуют аутентификации при каждом запросе .
Дополнительный уровень безопасности в этом сценарии добавил бы авторизацию клиентского приложения в дополнение к аутентификации пользователя. Например, если у вас есть веб-клиент, приложения для iOS и Android, все из которых используют веб-сервис, вы можете попросить сервер знать, какой из трех клиентов данного запроса, независимо от того, кто является аутентифицированным пользователем. Это может позволить вашему веб-сервису ограничить определенные функции определенными клиентами. Для этого вы можете использовать API ключи и секреты, см. Этот ответ для некоторых идей на этот счет.
Аутентификация в фейсбуке
Приведенный выше рабочий процесс не работает для подключения к Facebook, поскольку при входе через Facebook используется сторонняя организация, сама Facebook. Процедура входа требует, чтобы пользователь был перенаправлен на веб-сайт Facebook, где учетные данные вводятся вне нашего контроля.
Итак, давайте посмотрим, как все меняется:
- Пользователь подключается к
https://example.com
- Сервер обслуживает богатое приложение Javascript, которое отображает начальную страницу. Где-то на странице есть форма входа, которая включает кнопку «Войти через Facebook».
- Пользователь нажимает кнопку «Войти через Facebook», которая является просто ссылкой, на которую перенаправляется (например)
https://example.com/auth/facebook
.
https://example.com/auth/facebook
Маршрут обрабатывается passport.js (см документации )
- Все, что видит пользователь, - это то, что страница меняется, и теперь они находятся на странице, размещенной на Facebook, где им необходимо войти в систему и авторизовать наше веб-приложение. Это полностью вне нашего контроля.
- Пользователь входит в систему Facebook и дает разрешение нашему приложению, поэтому теперь Facebook перенаправляет обратно на URL-адрес обратного вызова, который мы настроили в настройке passport.js, что соответствует примеру в документации :
https://example.com/auth/facebook/callback
- Обработчик passport.js для
https://example.com/auth/facebook/callback
маршрута вызовет функцию обратного вызова, которая получает токен доступа Facebook и некоторую информацию о пользователе от Facebook, включая адрес электронной почты пользователя.
- С помощью электронной почты мы можем найти пользователя в нашей базе данных и сохранить с ним токен доступа Facebook.
- Последнее, что вы делаете в обратном вызове Facebook, - это перенаправляете обратно в приложение расширенного клиента, но на этот раз нам нужно передать имя пользователя и токен доступа клиенту, чтобы он мог их использовать. Это можно сделать несколькими способами. Например, переменные Javascript могут быть добавлены на страницу через серверный механизм шаблонов, или же файл cookie может быть возвращен с этой информацией. (спасибо @RyanKimber за указание на проблемы безопасности при передаче этих данных в URL, как я изначально предлагал).
- Итак, теперь мы запускаем одностраничное приложение еще раз, но у клиента есть имя пользователя и токен доступа.
- Клиентское приложение может немедленно инициировать событие входа в систему и позволить различным частям приложения запрашивать необходимую информацию из веб-службы.
- Все запросы отправлены
https://example.com/api
будут включать токен доступа Facebook для аутентификации или собственный токен доступа приложения, сгенерированный из токена Facebook через функцию «get_access_token» в REST API.
- В не-браузерных приложениях это немного сложнее, потому что для входа в систему OAuth требуется веб-браузер. Чтобы войти в систему с телефона или из настольного приложения, вам потребуется запустить браузер, чтобы выполнить перенаправление на Facebook, и, что еще хуже, вы нужно, чтобы браузер передавал маркер доступа Facebook обратно в приложение через какой-то механизм.
Я надеюсь, что это отвечает на большинство вопросов. Конечно, вы можете заменить Facebook на Twitter, Google или любой другой сервис аутентификации на основе OAuth.
Мне было бы интересно узнать, есть ли у кого-то более простой способ справиться с этим.
passport-facebook
. После того, как вы начнете работать, следующий шаг - начать понимать, как работает Passport и как он хранит учетные данные. Подключение к Restify ( см. Здесь обновленную версию упомянутой вами) будет одним из последних шагов (или вы можете реализовать интерфейс REST в Express).