- PVSM.RU - https://www.pvsm.ru -
От переводчика: Это третья статья из цикла о Node.js [1] от команды Mozilla Identity, которая занимается проектом Persona [2]. Эта статья посвящена применяемому в Persona способу хранения данных сессии на клиенте.
К сожалению, большинство веб-приложений должны хранить информацию о состоянии, чтобы предлагать пользователям персонализированные страницы. Если пользователи могут регистрироваться на сайте, то нам надо хранить сессии. Самый распространенный способ — установить cookie со случайным идентификатором сессии, а детали хранить на сервере.
Если необходимо масштабировать такой сайт, есть три варианта:
У всех этих подходов есть недостатки:
Тем не менее, поразмыслив немного, можно придумать и четвёртый способ: хранить все данные сессии на клиенте.
У хранения данных сессии в браузере есть несколько очевидных преимуществ:
Но есть одна большая проблема: данным, хранящимся у клиента, нельзя доверять. К примеру, если вы храните в cookie ID пользователя, то он может подменить его и получить доступ к чужой учётной записи.
Хоть эта проблема и кажется непреодолимой, у неё есть решение: хранить данные в защищённом контейнере. Таким образом, больше нет необходимости доверять клиенту — у него нет возможности незаметно их подменить.
На практике это означает, что данные в cookie надо зашифровать и подписать ключом, хранящимся на сервере. Именно этим занимается модуль client-sessions.
Библиотека node-client-sessions [5] для Node.js заменяет стандартные middleware-модули фреймворка Connect session [6] и cookie-parser [7]. Вот как включить её в простое приложение для Express:
const clientSessions = require("client-sessions");
app.use(clientSessions({
secret: '0GBlJZ9EKBt2Zbi2flRPvztczCewBxXK' // set this to a long random string!
}));
Затем можно устанавливать значения свойств объекта req.session
:
app.get('/login', function (req, res){
req.session.username = 'JohnDoe';
});
и считывать их:
app.get('/', function (req, res){
res.send('Welcome ' + req.session.username);
});
Для закрытия сессии служит метод reset()
:
app.get('/logout', function (req, res) {
req.session.reset();
});
Один из главных недостатков хранения сессий на клиенте состоит в том, что сервер больше не может закрывать сессии самостоятельно.
При хранении данных сессии на сервере достаточно просто удалить данные сессии из БД, после чего все cookie на всех клиентах буду указывать на несуществующую запись. Когда данные хранятся на клиенте, сервер не может быть уверен, что данные были удалены во всех браузерах. Другими словам, не так то просто синхронизировать новое состояние сервера (пользователь завершил сессию) с состоянием на клиенте (сессия открыта).
Чтобы немного снизить остроту проблемы, client-sessions хранит в cookie время жизни сессии. Прежде чем распаковывать данные из зашифрованного контейнера, сервер проверит, не просрочены ли они. Если да, то он проигнорирует эти данные и будет считать, что сессия закрыта.
Хотя схема с установкой времени жизни работает неплохо, особенно, если время не очень большое, в случае с Persona нам нужен был способ немедленно закрывать сессию на всех клиентах, если пользователь менял пароль.
Нам всё же пришлось хранить малую толику состояния на сервере. Мы сделали это [8], добавив одно поле в таблицу БД на сервере и в cookie.
Каждый вызов API, который обращается к данным сессии, теперь считывает это поле в БД и сравнивает его с аналогичным полем в cookie. Если они не совпадают, сессия считается закрытой.
Лишнее обращение к БД — это, конечно не очень хорошо, но, к счастью, нам и так приходилось читать из таблицы с данными пользователей при почти каждом вызове, так что идентификатор сессии можно было получить без лишних накладных расходов. Чтобы вы могли быстрее начать экспериментировать с модулем, мы написали небольшое демонстрационное приложение [9].
Продолжение следует...
Автор: ilya42
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/44746
Ссылки в тексте:
[1] цикла о Node.js: https://hacks.mozilla.org/category/a-node-js-holiday-season/
[2] Persona: http://ru.wikipedia.org/wiki/Mozilla_Persona
[3] Охотимся за утечками памяти в Node.js: http://habrahabr.ru/company/nordavind/blog/195494/
[4] Нагружаем Node под завязку: http://habrahabr.ru/company/nordavind/blog/195686/
[5] node-client-sessions: https://github.com/mozilla/node-client-sessions
[6] session: http://www.senchalabs.org/connect/session.html
[7] cookie-parser: http://www.senchalabs.org/connect/cookieParser.html
[8] Мы сделали это: https://github.com/mozilla/browserid/commit/1b0444d85700a951edc74a0bf7ad5581b2cbfedd
[9] демонстрационное приложение: https://github.com/fmarier/node-client-sessions-sample
[10] Источник: http://habrahabr.ru/post/196018/
Нажмите здесь для печати.