The session
module provides way to group HTTP requests into
"sessions" so that information can be maintained between an individual user's
requests to various parts of a web site - for example, so that a user can
"log in" to the web site and their username remembered as they navigate the
site.
The base Session
class is not used
directly, since it has no way of storing the data associated with a session.
Instead, one of the classes derived from it are used. The choice of subclass
determines what storage method is used - the module provides
FileSession
and
SQLSession
, or you can write your
own.
To store data in the session, you simply use it as a mapping. For example:
if "basket" in self.session:
self.session["basket"].append(newitem)
else:
self.session["basket"] = [newitem]
Sessions are identified by a unique 8-character hexadecimal string, which
is usually generated randomly. This is paired with another 8-character
hexadecimal string which is a keyed hash generated using the identifier and a
secret key unique to the individual web site. The hash simply makes it a bit
more difficult for an attacker to guess a valid session identifier. The id
and hash are stored in the session under the keys id
and
hash
, so don't try to use these keys for storing your own
data.
The session identifier and hash are passed from request to request either
using cookies or by embedding the data at the start of the path in the URL.
Which method to use depends on the situation - cookies are better, but some
users disable cookies in their browsers. An especially important point to note
is that if session identifiers are stored in URLs, any external links must go
through a doorway page which forwards the user (using something like
<meta http-equiv="refresh"...>
rather than HTTP redirects)
to the external page, because otherwise the session information may get passed
to the external site in the HTTP Referer
header.
To create and maintain the session, a session class should be instantiated
at the start of processing a request, and its
save
method called at the end of
processing.
Example:
class Handler(wt.Handler):
def process(self, req):
self.session = session.FileSession(req, "s3cr3t")
if not self.session.relocated:
wt.Handler.process(self, req)
self.session.save()
If you are passing the session identifier in the URL, then you will need to configure your web server so that it knows what to do with this identifier. If you are not embedding the session identifier in the URL, then no extra configuration of the web server is required.
Using Apache, you should use
mod_rewrite
to extract the session identifier from the URL and pass it in the
SESSION
environment variable. The URL is then modified to remove
the identifier so that the web server can find the requested page.
Example using httpd.conf
:
<VirtualHost 192.168.0.1>
ServerName www.example.com
...
RewriteEngine on
RewriteRule ^/([A-Fa-f0-9]{16})(/.*)$ $2 [E=SESSION:$1]
<VirtualHost>
Example using an .htaccesss
file in the web root directory:
RewriteEngine on
RewriteBase /
RewriteRule ^([A-Fa-f0-9]{16})(/.*)$ $2 [E=SESSION:$1]
If you are using the wt
templating module
in conjunction with the session
module, you should simply put the
single session
RewriteRule
line before the
wt
RewriteCond
line, e.g.:
RewriteEngine on
RewriteBase /
RewriteRule ^([A-Fa-f0-9]{16})(/.*)$ $2 [E=SESSION:$1]
RewriteCond %{DOCUMENT_ROOT}/wt/$1.py -f
RewriteRule ^(.*)$ /wt/$1.py [E=WT_TEMPLATE_URL:/$1,E=WT_TEMPLATE_FILENAME:%{DOCUMENT_ROOT}/$1]
The base class for all exceptions defined by the session
module.
Session
objects manage the session as well as providing
a container to store data associated with the session. This class is not used
directly, but is subclassed depending on what method is being used to store the
session data.
relocated
The relocated
map references a true value if URL-based sessions
are being used and a Location
header has been set to redirect the
user's browser to a new URL.
created
The number of seconds since the epoch (i.e. time.time()
value)
when this session was created.
new
new
references a true value if the session was created during
this request (i.e. there was no pre-existing session).
surl
This variable is only present if session identifiers are being
embedded in URLs for the current session. If it is present, it is the URL
prefix that is used for this purpose - e.g. /0a33817bc823781f/
.
__init__(self, req, secret, cookie="jonsid", url=0, root="",
referer=None, sid=None, shash=None)
req
:
cgi.Request
instance
secret
: string
cookie
: string
url
: true or false value
root
: string
referer
: string
sid
: string
shash
: string
This method may be overridden by subclasses. It creates a new
Session
instance. secret
is a secret key (i.e. any
arbitrary string that you do not disclose) which is used for keying the hash
used to verify session identifiers (see
_make_hash). This value should be unique for
each web site, unless you are deliberately trying to share session identifiers
between sites.
cookie
is the name of the session cookie which is used to store
the session identifier. There is usually no need to change this from the default
of jonsid
. If you do not wish to use cookies to identify the
session then set this parameter to None
.
If you wish to use session identifiers embedded in URLs then set
url
to a true value. You may then optionally also set
root
to be the web root at which sessions are anchored (i.e.
a string to put before the session identifier in the url). root
should begin with a /
character but should not end in one. When
using session identifiers in URLs, the session identifier will be looked for
in environment variables matching (REDIRECT_){1,4}SESSION
.
Instructions on how to configure Apache to provide this variable are shown
above.
You can optionally use the HTTP Referer
header to help with
session verification when using session identifiers in urls. If you set the
referer
parameter to a non-empty string (for example, the host
name of your web site) and the user's browser sends a Referer
header which does not contain that string, then the session is invalidated.
This helps avoid unwanted session sharing in the situation where a user emails
a URL to a friend. Note that this is not a security measure
but just a helpful heuristic, since the contents of this header are under user
control.
Finally, if you wish to identify the session in some other way, you can set
cookie
to None
and url
to 0
and then pass in the session identifier in sid
. You may optionally
also pass in the identifier hash in shash
- if you do then the
session identifier will be ignored and a new session created if the hash does
not match the identifier. If you omit the shash
parameter then the
identifier will be assumed correct.
After initialisation has completed, the session dictionary contains the
session identifier under key id
, the identifier hash under key
hash
, and if the session was not new, any stored information from
previous requests.
save(self)
This method may be overridden by subclasses. It stores the information from the current session's dictionary so that it may be retrieved in later requests. The default implementation does nothing.
tidy()
This method may be overridden by subclasses. It is used to delete session
information that has expired, and should therefore be called periodically,
perhaps from a cron
job. Subclass versions of this method may
require different parameters to the function - you cannot call this method
without knowing the particulars of the particular subclass being used. The
default implementation does nothing.
_req
The cgi.Request
instance passed
to the session's __init__
method.
_make_hash(self, sid, secret)
sid
: string
secret
: string
Returns: string
This method may be overridden by subclasses. It returns the 8-character
hexadecimal string which is a keyed hash of the session identifier
sid
and the secret key secret
. The default
implementation uses HMAC-SHA, and should not usually need to be overridden.
_create(self, secret)
secret
: string
This method may be overridden by subclasses. It creates a new unique
8-character hexadecimal session identifier and initialises it in whatever
storage system is being used. self["id"]
should be set to the
session identifier. Optionally, self["hash"]
may also be set to the
identifier hash. If the hash is not set then
_make_hash
will be called
subsequently to determine it. The default implementation simply sets
self["id"]
to a random identifier.
_load(self)
This method may be overridden by subclasses. It updates the session's
dictionary with whatever information the storage system has recorded about the
session with identifier self["id"]
. It should return 1
if the session identifier was located in the storage system, or 0
if it was not (in which case a new session will be created). The default
implementation simply returns 1
.
Note that this method should only return 0
if the session
information could not be located because it did not exist. If any other error
occurs (e.g. an I/O error while searching for the session), then an exception
should be raised as usual.
The FileSession
class is a subclass of
Session
that uses the filesystem to store
session data.
__init__(self, req, secret, basedir=None, **kwargs)
req
:
cgi.Request
instance
secret
: string
basedir
: string
Creates a new FileSession instance. Session data will be stored using
individual files in the filesystem, under the basedir
directory.
If basedir
is not specified then the environment variable
TMPDIR
is used instead, or if there is no such environment
variable then /tmp
is used. A directory is created under this
named jon-sessions-%d
where %d
is the current
user id. If this directory already exists then it must be owned by the current
user. req
, secret
, and kwargs
are passed
to the base class's __init__
method.
save(self)
The session's dictionary is written to the filesystem.
tidy(max_idle=0, max_age=0, basedir=None)
max_idle
: integer
max_age
: integer
basedir
: string
Deletes session files that have expired. If max_idle
is
non-zero then it is the maximum number of seconds old a file's modification
time may be before it is deleted. If max_age
is non-zero then it
is the maximum number of seconds old a session may be (since it was created)
before it is deleted.
_create(self, secret)
secret
: string
Creates the session identifier and its associated file.
_load(self)
Updates the session's dictionary with the stored information from the
session's file. Returns 0
if the file did not exist, otherwise
1
.
The SQLSession
class is a subclass of
Session
that uses an SQL database to store
session data.
__init__(self, req, secret, dbc, table="sessions", **kwargs)
req
:
cgi.Request
instance
secret
: string
dbc
: Python DB API Cursor
instance
table
: string
Creates a new SQLSession instance. Session data will be stored using
rows in an SQL table. The database is accessed via the Cursor
instance dbc
and the table name table
.
req
, secret
, and kwargs
are passed to
the base class's __init__
method.
The table must have at least the following fields:
CREATE TABLE sessions (
ID INT UNSIGNED NOT NULL,
hash VARCHAR(8) NOT NULL,
data BLOB NOT NULL,
created INT UNSIGNED NOT NULL,
updated INT UNSIGNED NOT NULL,
PRIMARY KEY (ID)
)
This class has only been tested with MySQL, although the intention is that it should work with any DB API database.
save(self)
The session's dictionary is written to the database.
tidy(dbc, table="sessions", max_idle=0, max_age=0)
dbc
: Python DB API Cursor
instance
table
: string
max_idle
: integer
max_age
: integer
Deletes session rows that have expired. If max_idle
is
non-zero then it is the maximum number of seconds old a session's
updated
time may be before it is deleted. If max_age
is non-zero then it is the maximum number of seconds old a session's
created
time may be before it is deleted.
_create(self, secret)
secret
: string
Creates the session identifier and its associated table row.
_load(self)
Updates the session's dictionary with the stored information from the
session's database row. Returns 0
if the row was not found,
otherwise 1
.
$Id: session.html,v 1.8 2003/02/07 14:38:11 jribbens Exp $