diff options
| author | Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> | 2011-03-24 12:07:09 -0400 |
|---|---|---|
| committer | Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> | 2011-03-24 12:07:09 -0400 |
| commit | 95e799d074de2e81914d513b4c331df1e738c00e (patch) | |
| tree | b3039037533610d8c86d82bb28f139d8a3777013 /docs/narr/sessions.rst | |
| parent | 22d3253a26767501827d86b56db3a9b79bef6c4e (diff) | |
| parent | b596e1812627c359908759d7a8d83c339f08e385 (diff) | |
| download | pyramid-95e799d074de2e81914d513b4c331df1e738c00e.tar.gz pyramid-95e799d074de2e81914d513b4c331df1e738c00e.tar.bz2 pyramid-95e799d074de2e81914d513b4c331df1e738c00e.zip | |
Merge remote branch 'source/master'
Conflicts:
docs/narr/hooks.rst
Diffstat (limited to 'docs/narr/sessions.rst')
| -rw-r--r-- | docs/narr/sessions.rst | 192 |
1 files changed, 187 insertions, 5 deletions
diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index de9add3b7..97e3ebc55 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -3,13 +3,18 @@ .. _sessions_chapter: -Session Objects -=============== +Sessions +======== A :term:`session` is a namespace which is valid for some period of continual activity that can be used to represent a user's interaction with a web application. +This chapter describes how to configure sessions, what session +implementations :app:`Pyramid` provides out of the box, how to store and +retrieve data from sessions, and two session-specific features: flash +messages, and cross-site request forgery attack prevention. + .. _using_the_default_session_factory: Using The Default Session Factory @@ -32,12 +37,12 @@ limitation: representation of the session is fewer than 4000. This is suitable only for very small data sets. -It is, however, digitally signed, and thus its data cannot easily be +It is digitally signed, however, and thus its data cannot easily be tampered with. You can configure this session factory in your :app:`Pyramid` application by using the ``session_factory`` argument to the -:class:`pyramid.config.Configurator` class: +:class:`~pyramid.config.Configurator` class: .. code-block:: python :linenos: @@ -113,7 +118,7 @@ documentation. Some gotchas: - Keys and values of session data must be *pickleable*. This means, - typically, that they must be instances of basic types of objects, + typically, that they are instances of basic types of objects, such as strings, lists, dictionaries, tuples, integers, etc. If you place an object in a session data key or value that is not pickleable, an error will be raised when the session is serialized. @@ -162,3 +167,180 @@ both types are available in :class:`pyramid.interfaces.ISession`. You might use the cookie implementation in the :mod:`pyramid.session` module as inspiration. +.. index:: + single: flash messages + +Flash Messages +-------------- + +"Flash messages" are simply a queue of message strings stored in the +:term:`session`. To use flash messaging, you must enable a :term:`session +factory` as described in :ref:`using_the_default_session_factory` or +:ref:`using_alternate_session_factories`. + +Flash messaging has two main uses: to display a status message only once to +the user after performing an internal redirect, and to allow generic code to +log messages for single-time display without having direct access to an HTML +template. The user interface consists of a number of methods of the +:term:`session` object. + +Using the ``session.flash`` Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To add a message to a flash message queue, use a session object's ``flash()`` +method: + +.. code-block:: python + + request.session.flash('mymessage') + +The ``flash()`` method appends a message to a flash queue, creating the queue +if necessary. + +``flash()`` accepts three arguments: + +.. method:: flash(message, queue='', allow_duplicate=True) + +The ``message`` argument is required. It represents a message you wish to +later display to a user. It is usually a string but the ``message`` you +provide is not modified in any way. + +The ``queue`` argument allows you to choose a queue to which to append +the message you provide. This can be used to push different kinds of +messages into flash storage for later display in different places on a +page. You can pass any name for your queue, but it must be a string. +Each queue is independent, and can be popped by ``pop_flash()`` or +examined via ``peek_flash()`` separately. ``queue`` defaults to the +empty string. The empty string represents the default flash message +queue. + +.. code-block:: python + + request.session.flash(msg, 'myappsqueue') + +The ``allow_duplicate`` argument defaults to ``True``. If this is +``False``, and you attempt to add a message value which is already +present in the queue, it will not be added. + +Using the ``session.pop_flash`` Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once one or more messages have been added to a flash queue by the +``session.flash()`` API, the ``session.pop_flash()`` API can be used to +pop an entire queue and return it for use. + +To pop a particular queue of messages from the flash object, use the session +object's ``pop_flash()`` method. This returns a list of the messages +that were added to the flash queue, and empties the queue. + +.. method:: pop_flash(queue='') + +.. code-block:: python + :linenos: + + >>> request.session.flash('info message') + >>> request.session.pop_flash() + ['info message'] + +Calling ``session.pop_flash()`` again like above without a corresponding call +to ``session.flash()`` will return an empty list, because the queue has already +been popped. + +.. code-block:: python + :linenos: + + >>> request.session.flash('info message') + >>> request.session.pop_flash() + ['info message'] + >>> request.session.pop_flash() + [] + +Using the ``session.peek_flash`` Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once one or more messages has been added to a flash queue by the +``session.flash()`` API, the ``session.peek_flash()`` API can be used to +"peek" at that queue. Unlike ``session.pop_flash()``, the queue is not +popped from flash storage. + +.. method:: peek_flash(queue='') + +.. code-block:: python + :linenos: + + >>> request.session.flash('info message') + >>> request.session.peek_flash() + ['info message'] + >>> request.session.peek_flash() + ['info message'] + >>> request.session.pop_flash() + ['info message'] + >>> request.session.peek_flash() + [] + +.. index:: + single: preventing cross-site request forgery attacks + single: cross-site request forgery attacks, prevention + +Preventing Cross-Site Request Forgery Attacks +--------------------------------------------- + +`Cross-site request forgery +<http://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a +phenomenon whereby a user with an identity on your website might click on a +URL or button on another website which unwittingly redirects the user to your +application to perform some command that requires elevated privileges. + +You can avoid most of these attacks by making sure that the correct *CSRF +token* has been set in an :app:`Pyramid` session object before performing any +actions in code which requires elevated privileges that is invoked via a form +post. To use CSRF token support, you must enable a :term:`session factory` +as described in :ref:`using_the_default_session_factory` or +:ref:`using_alternate_session_factories`. + +Using the ``session.get_csrf_token`` Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To get the current CSRF token from the session, use the +``session.get_csrf_token()`` method. + +.. code-block:: python + + token = request.session.get_csrf_token() + +The ``session.get_csrf_token()`` method accepts no arguments. It returns a +CSRF *token* string. If ``session.get_csrf_token()`` or +``session.new_csrf_token()`` was invoked previously for this session, the +existing token will be returned. If no CSRF token previously existed for +this session, a new token will be will be set into the session and returned. +The newly created token will be opaque and randomized. + +You can use the returned token as the value of a hidden field in a form that +posts to a method that requires elevated privileges. The handler for the +form post should use ``session.get_csrf_token()`` *again* to obtain the +current CSRF token related to the user from the session, and compare it to +the value of the hidden form field. For example, if your form rendering +included the CSRF token obtained via ``session.get_csrf_token()`` as a hidden +input field named ``csrf_token``: + +.. code-block:: python + :linenos: + + token = request.session.get_csrf_token() + if token != request.POST['csrf_token']: + raise ValueError('CSRF token did not match') + +Using the ``session.new_csrf_token`` Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To explicitly add a new CSRF token to the session, use the +``session.new_csrf_token()`` method. This differs only from +``session.get_csrf_token()`` inasmuch as it clears any existing CSRF token, +creates a new CSRF token, sets the token into the session, and returns the +token. + +.. code-block:: python + + token = request.session.new_csrf_token() + + |
