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, это приведёт к серьёзным проблемам!
Сохранение идентификатора сессии.
Большая часть состояния сессии хранится на сервере. Однако для сохранения ссылки на это состояние идентификатор сессии необходимо передавать между клиентом и сервером в обоих направлениях.
Проще всего это сделать с помощью cookie. Класс CGI::Session обеспечивает прозрачную передачу идентификатора сессии с помощью cookie, если у клиента они включены.
Если у клиента отключены cookie, идентификатор сессии необходимо включать в качестве параметра во все запросы, отправляемые клиентом серверу. Класс 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 289
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-
если значение истинно, принудительно создаёт новую сессию. Если параметр не задан, новая сессия создаётся, только если текущей сессии нет. Если значение ложно, новая сессия никогда не создаётся; если текущей сессии нет и параметр
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, используемую для добавления скрытых элементов ввода в формы.
ПРЕДУПРЕЖДЕНИЕ в режиме генерации HTML 4 поля output_hidden окружаются тегом <fieldset>, который во многих браузерах не является невидимым; возможно, вам понадобится отключить использование fieldset с помощью кода, подобного следующему (см. blade.ruby-lang.org/ruby-list/37805)
cgi = CGI.new("html4")
class << cgi
undef_method :fieldset
end
Общедоступные методы экземпляра
# File lib/cgi/session.rb, line 350 def [](key) @data ||= @dbman.restore @data[key] end
Получает данные сессии по ключу key.
# File lib/cgi/session.rb, line 356 def []=(key, val) @write_lock ||= true @data ||= @dbman.restore @data[key] = val end
Задаёт данные сессии для ключа key.
# File lib/cgi/session.rb, line 370 def close @dbman.close @dbprot.clear end
Сохраняет данные сессии на сервере и закрывает хранилище сессии. Для некоторых типов хранилищ сессий этот вызов ничего не делает.
# File lib/cgi/session.rb, line 379 def delete @dbman.delete @dbprot.clear end
Удаляет сессию из хранилища. Также закрывает хранилище.
Обратите внимание: данные сессии не удаляются автоматически по истечении срока её действия.
# File lib/cgi/session.rb, line 364 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–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.