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 |
[] |