Различные веб-фреймворки и языки по-разному подходят к вопросу, как хранить сессию пользователя, да и просто:
как её привязать к пользователю. Особые проблемы начинаются тогда, когда надо связывать разные технологии, например
сделать единую авторизацию для рельсового приложения, phpBB форума и стриминг-сервера.

Самый простой подход — немного доработанные рельсовые сессии.

Сессии в рельсах — CookieStore

Идея состоит в том, что вся информация, которая уходит пользователю по нешифрованному каналу итак открыта, поэтому
нечего бояться её показать. Плюс очень, очень не рекомендуется гонять в сессии целые объекты (как это сделано с
flash[:cart] в Agile Web Development On Rails).

Итак, в сессию складывается относительно небольшой объём информации: user_id, last_order_id (если нужно) и т.п.
Ничего страшного в том, что бы запалить id пользователя нет.

В рельсах такая сессия выглядит как хеш-таблица:

{:user_id => 15}

которая упакована с помощью Marshal — это универсальный сериализатор всех руби объектов, потом Base64 кодирована для
того, что бы можно было безопасно убрать в куку.

Вопрос: а как же удостовериться в том, что плохой пользователь не проделает то же самое и не присвоит себе
user_id админа?

Base64-кодированная сессия подписывается секретным ключом с помощью SHA1 и подпись подклеивается к сессии с разделителем: “—”. Вот пример такой куки:

BAh7CToPc2Vzc2lvbl9pZCIlNWQ3Y2EzNDBmZmM3ZDdiMWQzMzdiYmIyODI1MzA3NWM6DHVzZXJfaWRpAk4BOhBfY3NyZl90b2tlbiIxRmVwdWJNcT Bkd2VYekJ4MS8yVmZGb0g3Y1RyaGRyTTN3aC9ib2laTmdtaz0iCmZsYXNoSUM6J0FjdGlvbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhhc2h7BjoL bm90aWNlIhxTaWduZWQgaW4gc3VjY2Vzc2Z1bGx5LgY6CkB1c2VkewY7CUY%3D—d2ea88629596f21ea25d92c60ece7cca4841e6fe

Давайте её распакуем:

irb -rubygems -raction_pack -raction_controller -ractive_support encoded, sign = cookie.gsub(‘%3D’,‘=’).split(“—”) session = Marshal.load(Base64.decode64(encoded)) => {:session_id=>"5d7ca340ffc7d7b1d337bbb28253075c", :user_id=>334, :_csrf_token=>"FepubMq0dweXzBx1/2VfFoH7cTrhdrM3wh/boiZNgmk=", “flash”=>{:notice=>"Signed in successfully."}}

На самом деле, уже тут кроется небольшой обман:

session[“flash”].class

=> ActionController::Flash::FlashHash

С этой проблемой мы ещё столкнемся дальше.

Чем это круто? Да очень просто: пользователя можно совершенно спокойно перебросить на другой сервер, не создавая централизованное хранилище сессий. Плюс навсегда пропадает проблема зачистки старых сессий.

А чего там про PHP и почему у поста тег erlang?

37 Signals, внедряя CookieStore допустили очень серьезную ошибку в одном месте: они сделали Marshal.dump вместо JSON.encode.

Давайте посмотрим, как вся эта технология будет выглядеть, если сессия будет отправляться на браузер в виде обычного подписанного JSON-а. Пользователь приходит на рельсовую морду, получает такую куку, идёт на PHP-форум, где все эти механизмы сделаны точно так же! Вуа-ля, авторизация на смежных субпроектах получена бесплатно!

Но это не всё. На странице загружается флешка, берет куку, отдает её socket-серверу или RTMP-серверу, тот распаковывает эту сессию, на каком бы языке он ни был написан: JSON откроется везде, находит там user_id и подписывает это соединение на получение сообщений для user_id!

Более того, этот механизм уже есть и работает в erlyvideo!

JSON, Rails, Marshal, боль!

Проблемы начнутся в рельсах.

Во-первых, сессия в рельсах — не HashWithIndifferentAccess, а существенно более сложная штука. Символы и строки в руби —
разные сущности и в одном хеше может быть одновременно ключом как строка, так и символ и значения будут разные.
Ладно, это решаем административно: только символы и не волнует.

Во-вторых, flash. Это особый объект со своими проблемами.

Если не хочется вникать, то этот патч к MessageVerifier-у исправно работает в продакшне.

Наверное стоит начать процедуру пиления 37 Signals, что бы они сделали такую униформную штуку.

А чего там про PHP?

Да ничего. Я на нём 5 лет не писал, так что если кто-нибудь хочет, я помогу ему заимплементить этот механизм.

А erlyvideo?

Erlyvideo с этой концепцией полностью совместим. Давайте посмотрим на пример в contrib/chat. Для него
у вас должна стоять sinatra и rails:

gem install sinatra rails

Меняем для vhost-а default в ebin/erlmedia.app значение auth_module на json_session:

{auth_module, json_session},

и выбираем secret_key подлиннее

Теперь

ems:restart().

После этого запускаем руби-сервер:

./chat.rb open http://localhost:4567/ open http://localhost:8082/chat.html

В первом окне вы видите подключение со страницы, сгенеренной руби-сервером, во втором окне тестовый пример работы
erlyvideo.

Вы можете попробовать вводить данные в обоих окошках и початиться. Что же в этом всём необычного?
Да то, что флешка в обоих случаях не может представиться другим пользователем. Какой user_id ей отдался в сессии,
так её erlyvideo и признает, подделать не получится. Соответственно, erlyvideo подпишет именно на те каналы,
на которые надо.

Проверку на валидность посылки можно осуществить в хендлере post ‘/say’ в chat.rb

Sidebar