Steve Piercy
2017-06-27 582a27558f96552cc84641c603150a21a8000821
commit | author | age
04ebd5 1 .. index::
CM 2    single: session
3
4 .. _sessions_chapter:
5
b0b9f7 6 Sessions
CD 7 ========
04ebd5 8
42049e 9 A :term:`session` is a namespace which is valid for some period of continual
SP 10 activity that can be used to represent a user's interaction with a web
11 application.
04ebd5 12
42049e 13 This chapter describes how to configure sessions, what session implementations
SP 14 :app:`Pyramid` provides out of the box, how to store and retrieve data from
313c25 15 sessions, and a session-specific feature: flash messages.
089c63 16
6ce1e0 17 .. index::
CM 18    single: session factory (default)
19
4df636 20 .. _using_the_default_session_factory:
CM 21
42049e 22 Using the Default Session Factory
04ebd5 23 ---------------------------------
CM 24
42049e 25 In order to use sessions, you must set up a :term:`session factory` during your
SP 26 :app:`Pyramid` configuration.
04ebd5 27
42049e 28 A very basic, insecure sample session factory implementation is provided in the
SP 29 :app:`Pyramid` core.  It uses a cookie to store session information.  This
30 implementation has the following limitations:
04ebd5 31
42049e 32 - The session information in the cookies used by this implementation is *not*
SP 33   encrypted, so it can be viewed by anyone with access to the cookie storage of
34   the user's browser or anyone with access to the network along which the
35   cookie travels.
04ebd5 36
42049e 37 - The maximum number of bytes that are storable in a serialized representation
SP 38   of the session is fewer than 4000.  This is suitable only for very small data
39   sets.
04ebd5 40
42049e 41 It is digitally signed, however, and thus its data cannot easily be tampered
SP 42 with.
04ebd5 43
42049e 44 You can configure this session factory in your :app:`Pyramid` application by
SP 45 using the :meth:`pyramid.config.Configurator.set_session_factory` method.
04ebd5 46
CM 47 .. code-block:: python
48    :linenos:
49
8df7a7 50    from pyramid.session import SignedCookieSessionFactory
MM 51    my_session_factory = SignedCookieSessionFactory('itsaseekreet')
52
d7f259 53    from pyramid.config import Configurator
8df7a7 54    config = Configurator()
MM 55    config.set_session_factory(my_session_factory)
04ebd5 56
7cb892 57 .. warning::
04ebd5 58
8df7a7 59    By default the :func:`~pyramid.session.SignedCookieSessionFactory`
42049e 60    implementation is *unencrypted*.  You should not use it when you keep
SP 61    sensitive information in the session object, as the information can be
62    easily read by both users of your application and third parties who have
63    access to your users' network traffic.  And, if you use this sessioning
64    implementation, and you inadvertently create a cross-site scripting
65    vulnerability in your application, because the session data is stored
66    unencrypted in a cookie, it will also be easier for evildoers to obtain the
67    current user's cross-site scripting token.  In short, use a different
68    session factory implementation (preferably one which keeps session data on
69    the server) for anything but the most basic of applications where "session
70    security doesn't matter", and you are sure your application has no
76430b 71    cross-site scripting vulnerabilities.
6ce1e0 72
CM 73 .. index::
74    single: session object
04ebd5 75
CM 76 Using a Session Object
77 ----------------------
78
42049e 79 Once a session factory has been configured for your application, you can access
SP 80 session objects provided by the session factory via the ``session`` attribute
81 of any :term:`request` object.  For example:
04ebd5 82
CM 83 .. code-block:: python
84    :linenos:
85
94b889 86    from pyramid.response import Response
04ebd5 87
CM 88    def myview(request):
89        session = request.session
90        if 'abc' in session:
91            session['fred'] = 'yes'
92        session['abc'] = '123'
93        if 'fred' in session:
94            return Response('Fred was in the session')
95        else:
96            return Response('Fred was not in the session')
97
42049e 98 The first time this view is invoked produces ``Fred was not in the session``.
SP 99 Subsequent invocations produce ``Fred was in the session``, assuming of course
100 that the client side maintains the session's identity across multiple requests.
190b56 101
04ebd5 102 You can use a session much like a Python dictionary.  It supports all
42049e 103 dictionary methods, along with some extra attributes and methods.
04ebd5 104
CM 105 Extra attributes:
106
107 ``created``
108   An integer timestamp indicating the time that this session was created.
109
110 ``new``
42049e 111   A boolean.  If ``new`` is True, this session is new.  Otherwise, it has been
SP 112   constituted from data that was already serialized.
04ebd5 113
CM 114 Extra methods:
115
116 ``changed()``
42049e 117   Call this when you mutate a mutable value in the session namespace. See the
SP 118   gotchas below for details on when and why you should call this.
04ebd5 119
CM 120 ``invalidate()``
42049e 121   Call this when you want to invalidate the session (dump all data, and perhaps
SP 122   set a clearing cookie).
04ebd5 123
42049e 124 The formal definition of the methods and attributes supported by the session
SP 125 object are in the :class:`pyramid.interfaces.ISession` documentation.
04ebd5 126
CM 127 Some gotchas:
128
42049e 129 - Keys and values of session data must be *pickleable*.  This means, typically,
SP 130   that they are instances of basic types of objects, such as strings, lists,
131   dictionaries, tuples, integers, etc.  If you place an object in a session
132   data key or value that is not pickleable, an error will be raised when the
133   session is serialized.
04ebd5 134
42049e 135 - If you place a mutable value (for example, a list or a dictionary) in a
SP 136   session object, and you subsequently mutate that value, you must call the
137   ``changed()`` method of the session object. In this case, the session has no
138   way to know that it was modified.  However, when you modify a session object
139   directly, such as setting a value (i.e., ``__setitem__``), or removing a key
140   (e.g., ``del`` or ``pop``), the session will automatically know that it needs
141   to re-serialize its data, thus calling ``changed()`` is unnecessary. There is
142   no harm in calling ``changed()`` in either case, so when in doubt, call it
143   after you've changed sessioning data.
04ebd5 144
7d4a81 145 .. index::
a5da4d 146    single: pyramid_redis_sessions
6ce1e0 147    single: session factory (alternates)
7d4a81 148
4df636 149 .. _using_alternate_session_factories:
CM 150
04ebd5 151 Using Alternate Session Factories
CM 152 ---------------------------------
153
5ac519 154 The following session factories exist at the time of this writing.
SP 155
156 ======================= ======= =============================
157 Session Factory         Backend   Description
158 ======================= ======= =============================
bf22ed 159 pyramid_nacl_session_   PyNaCl_ Defines an encrypting,
SP 160                                 pickle-based cookie
161                                 serializer, using PyNaCl to
162                                 generate the symmetric
163                                 encryption for the cookie
164                                 state.
5ac519 165 pyramid_redis_sessions_ Redis_  Server-side session library
SP 166                                 for Pyramid, using Redis for
167                                 storage.
168 pyramid_beaker_         Beaker_ Session factory for Pyramid
169                                 backed by the Beaker
170                                 sessioning system.
171 ======================= ======= =============================
172
bf22ed 173 .. _pyramid_nacl_session: https://pypi.python.org/pypi/pyramid_nacl_session
SP 174 .. _PyNaCl: https://pynacl.readthedocs.io/en/latest/secret/
175
5ac519 176 .. _pyramid_redis_sessions: https://pypi.python.org/pypi/pyramid_redis_sessions
7b1612 177 .. _Redis: https://redis.io/
5ac519 178
SP 179 .. _pyramid_beaker: https://pypi.python.org/pypi/pyramid_beaker
7b1612 180 .. _Beaker: https://beaker.readthedocs.io/en/latest/
04ebd5 181
7d4a81 182 .. index::
6ce1e0 183    single: session factory (custom)
7d4a81 184
04ebd5 185 Creating Your Own Session Factory
CM 186 ---------------------------------
187
42049e 188 If none of the default or otherwise available sessioning implementations for
SP 189 :app:`Pyramid` suit you, you may create your own session object by implementing
190 a :term:`session factory`.  Your session factory should return a
191 :term:`session`.  The interfaces for both types are available in
04ebd5 192 :class:`pyramid.interfaces.ISessionFactory` and
42049e 193 :class:`pyramid.interfaces.ISession`. You might use the cookie implementation
SP 194 in the :mod:`pyramid.session` module as inspiration.
04ebd5 195
b0b9f7 196 .. index::
CD 197    single: flash messages
198
49d634 199 .. _flash_messages:
PE 200
b0b9f7 201 Flash Messages
CD 202 --------------
203
204 "Flash messages" are simply a queue of message strings stored in the
205 :term:`session`.  To use flash messaging, you must enable a :term:`session
206 factory` as described in :ref:`using_the_default_session_factory` or
207 :ref:`using_alternate_session_factories`.
208
42049e 209 Flash messaging has two main uses: to display a status message only once to the
SP 210 user after performing an internal redirect, and to allow generic code to log
211 messages for single-time display without having direct access to an HTML
b0b9f7 212 template. The user interface consists of a number of methods of the
CD 213 :term:`session` object.
6ce1e0 214
CM 215 .. index::
216    single: session.flash
b0b9f7 217
CD 218 Using the ``session.flash`` Method
219 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
220
fd3988 221 To add a message to a flash message queue, use a session object's ``flash()``
b0b9f7 222 method:
CD 223
224 .. code-block:: python
225
226    request.session.flash('mymessage')
227
fd3988 228 The ``flash()`` method appends a message to a flash queue, creating the queue
7cb892 229 if necessary.
b0b9f7 230
fd3988 231 ``flash()`` accepts three arguments:
b0b9f7 232
CD 233 .. method:: flash(message, queue='', allow_duplicate=True)
234
235 The ``message`` argument is required.  It represents a message you wish to
236 later display to a user.  It is usually a string but the ``message`` you
237 provide is not modified in any way.
238
42049e 239 The ``queue`` argument allows you to choose a queue to which to append the
SP 240 message you provide.  This can be used to push different kinds of messages into
241 flash storage for later display in different places on a page.  You can pass
242 any name for your queue, but it must be a string. Each queue is independent,
243 and can be popped by ``pop_flash()`` or examined via ``peek_flash()``
244 separately.  ``queue`` defaults to the empty string.  The empty string
245 represents the default flash message queue.
b0b9f7 246
CD 247 .. code-block:: python
248
249    request.session.flash(msg, 'myappsqueue')
250
42049e 251 The ``allow_duplicate`` argument defaults to ``True``.  If this is ``False``,
SP 252 and you attempt to add a message value which is already present in the queue,
253 it will not be added.
b0b9f7 254
6ce1e0 255 .. index::
CM 256    single: session.pop_flash
257
b0b9f7 258 Using the ``session.pop_flash`` Method
CD 259 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
260
261 Once one or more messages have been added to a flash queue by the
42049e 262 ``session.flash()`` API, the ``session.pop_flash()`` API can be used to pop an
SP 263 entire queue and return it for use.
b0b9f7 264
CD 265 To pop a particular queue of messages from the flash object, use the session
42049e 266 object's ``pop_flash()`` method. This returns a list of the messages that were
SP 267 added to the flash queue, and empties the queue.
b0b9f7 268
CD 269 .. method:: pop_flash(queue='')
270
b5fcc4 271 .. testsetup::
SP 272
273    from pyramid import testing
274    request = testing.DummyRequest()
275
276 .. doctest::
277
278    >>> request.session.flash('info message')
279    >>> request.session.pop_flash()
280    ['info message']
b0b9f7 281
CD 282 Calling ``session.pop_flash()`` again like above without a corresponding call
fd3988 283 to ``session.flash()`` will return an empty list, because the queue has already
b0b9f7 284 been popped.
CD 285
b5fcc4 286 .. doctest::
SP 287
288    >>> request.session.flash('info message')
289    >>> request.session.pop_flash()
290    ['info message']
291    >>> request.session.pop_flash()
292    []
6ce1e0 293
CM 294 .. index::
295    single: session.peek_flash
b0b9f7 296
CD 297 Using the ``session.peek_flash`` Method
298 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
299
42049e 300 Once one or more messages have been added to a flash queue by the
SP 301 ``session.flash()`` API, the ``session.peek_flash()`` API can be used to "peek"
302 at that queue.  Unlike ``session.pop_flash()``, the queue is not popped from
303 flash storage.
b0b9f7 304
CD 305 .. method:: peek_flash(queue='')
306
b5fcc4 307 .. doctest::
SP 308
309    >>> request.session.flash('info message')
310    >>> request.session.peek_flash()
311    ['info message']
312    >>> request.session.peek_flash()
313    ['info message']
314    >>> request.session.pop_flash()
315    ['info message']
316    >>> request.session.peek_flash()
317    []