class CGI::Session
Обзор
Этот файл предоставляет класс CGI::Session, который обеспечивает поддержку сессий для скриптов CGI. Сессия — это последовательность HTTP-запросов и ответов, связанных вместе и ассоциированных с одним клиентом. Информация, связанная с сессией, хранится на сервере между запросами. Идентификатор сессии передается между клиентом и сервером с каждым запросом и ответом, прозрачно для пользователя. Это добавляет информацию о состоянии в протокол HTTP-запроса/ответа, который по своей природе бессостоятелен.
Жизненный цикл
Экземпляр CGI::Session создаётся из объекта CGI. По умолчанию этот экземпляр CGI::Session начнёт новую сессию, если текущей нет, или продолжит текущую сессию для этого клиента, если она существует. Опция new_session может быть использована для того, чтобы всегда или никогда не создавать новую сессию. Более подробную информацию смотрите в методе new().
delete() удаляет сессию из хранилища сессий. Однако он не удаляет идентификатор сессии с клиента. Если клиент делает другой запрос с тем же идентификатором, эффект будет заключаться в запуске новой сессии с идентификатором старой сессии.
Установка и получение данных сессии
Класс Session ассоциирует данные с сессией как пары ключ-значение. Эти данные могут быть установлены и получены путём индексирования экземпляра Session с использованием [], так же как и для хэшей (хотя другие методы работы с хэшами не поддерживаются).
После завершения обработки сессии для запроса сессия должна быть закрыта с помощью метода close(). Это сохранит состояние сессии в постоянном хранилище. Если вы хотите сохранить состояние сессии в постоянном хранилище, не завершая обработку сессии для этого запроса, вызовите метод update().
Хранение состояния сессии
Вызывающий код может указать какой вид хранилища использовать для данных сессии, используя опцию database_manager для метода CGI::Session::new. Следующие классы хранения предоставляются как часть стандартной библиотеки:
-
CGI::Session::FileStore -
хранит данные как обычный текст в плоском файле. Работает только с данными типа
String. Это тип хранения по умолчанию. -
CGI::Session::MemoryStore -
хранит данные в хэше в оперативной памяти. Данные сохраняются только до тех пор, пока существует текущий экземпляр интерпретатора Ruby.
-
CGI::Session::PStore -
хранит данные в формате Marshalled. Предоставляется файлом cgi/session/pstore.rb. Поддерживает данные любого типа и предоставляет блокировку файлов и поддержку транзакций.
Также могут быть созданы пользовательские типы хранилища путём определения класса с последующими методами:
new(session, options) restore # returns hash of session data. update close delete
Изменение типа хранилища в процессе сессии не работает. Обратите внимание, что по умолчанию файлы данных сессии FileStore и PStore имеют одинаковое имя. Если ваше приложение переключается с одного на другой, не убедившись, что имена файлов будут отличаться, и клиенты всё ещё имеют старые сессии в cookie, то всё сломается!
Поддержание идентификатора сессии
Большая часть состояния сессии поддерживается на сервере. Однако, идентификатор сессии должен передаваться взад и вперёд между клиентом и сервером для поддержания ссылки на это состояние сессии.
Самый простой способ сделать это — через куки. Класс CGI::Session предоставляет прозрачную поддержку обмена идентификатором сессии через куки, если у клиента включены куки.
Если у клиента куки отключены, идентификатор сессии должен быть включён как параметр во все запросы, отправляемые клиентом на сервер. Класс CGI::Session в связке с классом CGI прозрачно добавит идентификатор сессии как скрытое поле ввода ко всем формам, сгенерированным с помощью метода HTML-генерации CGI#form(). Встроенная поддержка других механизмов, таких как переписывание URL, не предусмотрена. Вызывающий код отвечает за извлечение идентификатора сессии из атрибута session_id и его ручную кодировку в URL и добавление его как скрытого ввода в HTML-формы, созданные другими механизмами. Также, истечение срока действия сессии не обрабатывается автоматически.
Примеры использования
Установка имени пользователя
require 'cgi'
require 'cgi/session'
require 'cgi/session/pstore' # provides CGI::Session::PStore
cgi = CGI.new("html4")
session = CGI::Session.new(cgi,
'database_manager' => CGI::Session::PStore, # use PStore
'session_key' => '_rb_sess_id', # custom session key
'session_expires' => Time.now + 30 * 60, # 30 minute timeout
'prefix' => 'pstore_sid_') # PStore option
if cgi.has_key?('user_name') and cgi['user_name'] != ''
# coerce to String: cgi[] returns the
# string-like CGI::QueryExtension::Value
session['user_name'] = cgi['user_name'].to_s
elsif !session['user_name']
session['user_name'] = "guest"
end
session.close
Безопасное создание новой сессии
require 'cgi'
require 'cgi/session'
cgi = CGI.new("html4")
# We make sure to delete an old session if one exists,
# not just to free resources, but to prevent the session
# from being maliciously hijacked later on.
begin
session = CGI::Session.new(cgi, 'new_session' => false)
session.delete
rescue ArgumentError # if no old session
end
session = CGI::Session.new(cgi, 'new_session' => true)
session.close
Атрибуты
Идентификатор этой сессии.
Идентификатор этой сессии.
Методы публичного класса
# File lib/cgi/session.rb, line 248
def initialize(request, option={})
@new_session = false
session_key = option['session_key'] || '_session_id'
session_id = option['session_id']
unless session_id
if option['new_session']
session_id = create_new_id
@new_session = true
end
end
unless session_id
if request.key?(session_key)
session_id = request[session_key]
session_id = session_id.read if session_id.respond_to?(:read)
end
unless session_id
session_id, = request.cookies[session_key]
end
unless session_id
unless option.fetch('new_session', true)
raise ArgumentError, "session_key `%s' should be supplied"%session_key
end
session_id = create_new_id
@new_session = true
end
end
@session_id = session_id
dbman = option['database_manager'] || FileStore
begin
@dbman = dbman::new(self, option)
rescue NoSession
unless option.fetch('new_session', true)
raise ArgumentError, "invalid session_id `%s'"%session_id
end
session_id = @session_id = create_new_id unless session_id
@new_session=true
retry
end
request.instance_eval do
@output_hidden = {session_key => session_id} unless option['no_hidden']
@output_cookies = [
Cookie::new("name" => session_key,
"value" => session_id,
"expires" => option['session_expires'],
"domain" => option['session_domain'],
"secure" => option['session_secure'],
"path" =>
if option['session_path']
option['session_path']
elsif ENV["SCRIPT_NAME"]
File::dirname(ENV["SCRIPT_NAME"])
else
""
end)
] unless option['no_cookies']
end
@dbprot = [@dbman]
ObjectSpace::define_finalizer(self, Session::callback(@dbprot))
end Создать новый объект CGI::Session для request.
request — экземпляр класса CGI (см. cgi.rb). option — хеш параметров для инициализации экземпляра CGI::Session. Поддерживаются следующие параметры:
- session_key
-
Имя параметра, используемого для идентификатора сессии. По умолчанию '_session_id'.
-
session_id -
Идентификатор сессии. Если не указан, извлекается из параметра
session_keyзапроса или генерируется автоматически для новой сессии. -
new_session -
Если true, принудительно создать новую сессию. Если не задано, новая сессия создается только если текущей нет. Если false, новая сессия никогда не создаётся, и если текущей нет, а параметр
session_idне задан, генерируется исключениеArgumentError. - database_manager
-
Имя класса, обеспечивающего хранение состояния сессии. Встроена поддержка
FileStore(по умолчанию),MemoryStore, иPStore(из cgi/session/pstore.rb). Подробности в документации этих классов.
Следующие параметры также поддерживаются, но применяются только если идентификатор сессии хранится в cookie.
- session_expires
-
Время истечения текущей сессии, как объект
Time. Если не указано, сессия прекратится при закрытии браузера. - session_domain
-
Домен хоста, для которого действительна эта сессия. Если не указано, по умолчанию используется хост сервера.
- session_secure
-
Если
true, эта сессия будет работать только по HTTPS. - session_path
-
Путь, для которого действует эта сессия. По умолчанию, директория скрипта
CGI.
option также передаётся в инициализатор класса хранения сессий; см. документацию для каждого класса хранения сессий для поддержки параметров.
Полученная или созданная сессия автоматически добавляется в request как cookie, а также в таблицу output_hidden, которая используется для добавления скрытых элементов формы.
ВНИМАНИЕ поля output_hidden окружены тэгом <fieldset> в HTML 4, что не является невидимым во многих браузерах; вы можете отключить использование fieldset с кодом, подобным следующему (см. blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/37805)
cgi = CGI.new("html4")
class << cgi
undef_method :fieldset
end
Методы публичного экземпляра
# File lib/cgi/session.rb, line 309 def [](key) @data ||= @dbman.restore @data[key] end
Получить данные сессии для ключа key.
# File lib/cgi/session.rb, line 315 def []=(key, val) @write_lock ||= true @data ||= @dbman.restore @data[key] = val end
Set данные сессии для ключа key.
# File lib/cgi/session.rb, line 329 def close @dbman.close @dbprot.clear end
Сохранить данные сессии на сервере и закрыть хранилище сессий. Для некоторых типов хранилищ сессий это пустая операция.
# File lib/cgi/session.rb, line 338 def delete @dbman.delete @dbprot.clear end
Удалить сессию из хранилища. Также закрывает хранилище.
Обратите внимание, что данные сессии не удаляются автоматически при истечении сессии.
# File lib/cgi/session.rb, line 323 def update @dbman.update end
Сохранить данные сессии на сервере. Для некоторых типов хранилищ сессий это пустая операция.
Методы приватного экземпляра
# File lib/cgi/session.rb, line 171
def create_new_id
require 'securerandom'
begin
# by OpenSSL, or system provided entropy pool
session_id = SecureRandom.hex(16)
rescue NotImplementedError
# never happens on modern systems
require 'digest'
d = Digest('SHA512').new
now = Time::now
d.update(now.to_s)
d.update(String(now.usec))
d.update(String(rand(0)))
d.update(String($$))
d.update('foobar')
session_id = d.hexdigest[0, 32]
end
session_id
end Создать новый идентификатор сессии.
Идентификатор сессии — это безопасное случайное число, сгенерированное SecureRandom, если возможно, в противном случае — SHA512 хеш на основе времени, случайного числа и константы. Эта функция используется внутри для автоматической генерации идентификаторов сессий.
Ruby Core © 1993–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.