forked from orbit-oss/flask
Refactored session interface
This commit is contained in:
parent
1a61b12dbf
commit
0fccfe711f
6 changed files with 59 additions and 49 deletions
4
CHANGES
4
CHANGES
|
|
@ -8,6 +8,10 @@ Version 0.8
|
|||
|
||||
Relase date to be decided, codename to be chosen.
|
||||
|
||||
- Refactored session support into a session interface so that
|
||||
the implementation of the sessions can be changed without
|
||||
having to override the Flask class.
|
||||
|
||||
Version 0.7.2
|
||||
-------------
|
||||
|
||||
|
|
|
|||
25
docs/api.rst
25
docs/api.rst
|
|
@ -195,9 +195,34 @@ To access the current session you can use the :class:`session` object:
|
|||
session will be deleted when the user closes the browser.
|
||||
|
||||
|
||||
Session Interface
|
||||
-----------------
|
||||
|
||||
.. versionadded:: 0.7
|
||||
|
||||
The session interface provides a simple way to replace the session
|
||||
implementation that Flask is using.
|
||||
|
||||
.. currentmodule:: flask.sessions
|
||||
|
||||
.. autoclass:: SessionInterface
|
||||
:members:
|
||||
|
||||
.. autoclass:: SecureCookieSessionInterface
|
||||
:members:
|
||||
|
||||
.. autoclass:: NullSession
|
||||
:members:
|
||||
|
||||
.. autoclass:: SessionMixin
|
||||
:members:
|
||||
|
||||
|
||||
Application Globals
|
||||
-------------------
|
||||
|
||||
.. currentmodule:: flask
|
||||
|
||||
To share data that is valid for one request only from one function to
|
||||
another, a global variable is not good enough because it would break in
|
||||
threaded environments. Flask provides you with a special object that
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ from .ctx import has_request_context
|
|||
from .module import Module
|
||||
from .blueprints import Blueprint
|
||||
from .templating import render_template, render_template_string
|
||||
from .session import Session
|
||||
|
||||
# the signals
|
||||
from .signals import signals_available, template_rendered, request_started, \
|
||||
|
|
|
|||
38
flask/app.py
38
flask/app.py
|
|
@ -27,7 +27,7 @@ from .wrappers import Request, Response
|
|||
from .config import ConfigAttribute, Config
|
||||
from .ctx import RequestContext
|
||||
from .globals import _request_ctx_stack, request
|
||||
from .session import Session, _NullSession
|
||||
from .sessions import SecureCookieSessionInterface
|
||||
from .module import blueprint_is_module
|
||||
from .templating import DispatchingJinjaLoader, Environment, \
|
||||
_default_template_ctx_processor
|
||||
|
|
@ -211,6 +211,12 @@ class Flask(_PackageBoundObject):
|
|||
#: .. versionadded:: 0.7
|
||||
test_client_class = None
|
||||
|
||||
#: the session interface to use. By default an instance of
|
||||
#: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.
|
||||
#:
|
||||
#: .. versionadded:: 0.7
|
||||
session_interface = SecureCookieSessionInterface()
|
||||
|
||||
def __init__(self, import_name, static_path=None, static_url_path=None,
|
||||
static_folder='static', template_folder='templates'):
|
||||
_PackageBoundObject.__init__(self, import_name,
|
||||
|
|
@ -580,32 +586,32 @@ class Flask(_PackageBoundObject):
|
|||
def open_session(self, request):
|
||||
"""Creates or opens a new session. Default implementation stores all
|
||||
session data in a signed cookie. This requires that the
|
||||
:attr:`secret_key` is set.
|
||||
:attr:`secret_key` is set. Instead of overriding this method
|
||||
we recommend replacing the :class:`session_interface`.
|
||||
|
||||
:param request: an instance of :attr:`request_class`.
|
||||
"""
|
||||
key = self.secret_key
|
||||
if key is not None:
|
||||
return Session.load_cookie(request, self.session_cookie_name,
|
||||
secret_key=key)
|
||||
return self.session_interface.open_session(self, request)
|
||||
|
||||
def save_session(self, session, response):
|
||||
"""Saves the session if it needs updates. For the default
|
||||
implementation, check :meth:`open_session`.
|
||||
implementation, check :meth:`open_session`. Instead of overriding this
|
||||
method we recommend replacing the :class:`session_interface`.
|
||||
|
||||
:param session: the session to be saved (a
|
||||
:class:`~werkzeug.contrib.securecookie.SecureCookie`
|
||||
object)
|
||||
:param response: an instance of :attr:`response_class`
|
||||
"""
|
||||
expires = domain = None
|
||||
if session.permanent:
|
||||
expires = datetime.utcnow() + self.permanent_session_lifetime
|
||||
if self.config['SERVER_NAME'] is not None:
|
||||
# chop of the port which is usually not supported by browsers
|
||||
domain = '.' + self.config['SERVER_NAME'].rsplit(':', 1)[0]
|
||||
session.save_cookie(response, self.session_cookie_name,
|
||||
expires=expires, httponly=True, domain=domain)
|
||||
return self.session_interface.save_session(self, session, response)
|
||||
|
||||
def make_null_session(self):
|
||||
"""Creates a new instance of a missing session. Instead of overriding
|
||||
this method we recommend replacing the :class:`session_interface`.
|
||||
|
||||
.. versionadded:: 0.7
|
||||
"""
|
||||
return self.session_interface.make_null_session(self)
|
||||
|
||||
def register_module(self, module, **options):
|
||||
"""Registers a module with this application. The keyword argument
|
||||
|
|
@ -1184,7 +1190,7 @@ class Flask(_PackageBoundObject):
|
|||
"""
|
||||
ctx = _request_ctx_stack.top
|
||||
bp = ctx.request.blueprint
|
||||
if not isinstance(ctx.session, _NullSession):
|
||||
if not self.session_interface.is_null_session(ctx.session):
|
||||
self.save_session(ctx.session, response)
|
||||
funcs = ()
|
||||
if bp is not None and bp in self.after_request_funcs:
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ class RequestContext(object):
|
|||
# request context (e.g. flask-sqlalchemy).
|
||||
self.session = self.app.open_session(self.request)
|
||||
if self.session is None:
|
||||
self.session = _NullSession()
|
||||
self.session = self.app.make_null_session()
|
||||
|
||||
def pop(self):
|
||||
"""Pops the request context and unbinds it by doing that. This will
|
||||
|
|
|
|||
|
|
@ -3,41 +3,17 @@
|
|||
flask.session
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Implements cookie based sessions based on Werkzeug's secure cookie
|
||||
system.
|
||||
This module used to flask with the session global so we moved it
|
||||
over to flask.sessions
|
||||
|
||||
:copyright: (c) 2010 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from werkzeug.contrib.securecookie import SecureCookie
|
||||
from warnings import warn
|
||||
warn(DeprecationWarning('please use flask.sessions instead'))
|
||||
|
||||
from .sessions import *
|
||||
|
||||
class Session(SecureCookie):
|
||||
"""Expands the session with support for switching between permanent
|
||||
and non-permanent sessions.
|
||||
"""
|
||||
|
||||
def _get_permanent(self):
|
||||
return self.get('_permanent', False)
|
||||
|
||||
def _set_permanent(self, value):
|
||||
self['_permanent'] = bool(value)
|
||||
|
||||
permanent = property(_get_permanent, _set_permanent)
|
||||
del _get_permanent, _set_permanent
|
||||
|
||||
|
||||
class _NullSession(Session):
|
||||
"""Class used to generate nicer error messages if sessions are not
|
||||
available. Will still allow read-only access to the empty session
|
||||
but fail on setting.
|
||||
"""
|
||||
|
||||
def _fail(self, *args, **kwargs):
|
||||
raise RuntimeError('the session is unavailable because no secret '
|
||||
'key was set. Set the secret_key on the '
|
||||
'application to something unique and secret.')
|
||||
__setitem__ = __delitem__ = clear = pop = popitem = \
|
||||
update = setdefault = _fail
|
||||
del _fail
|
||||
Session = SecureCookieSession
|
||||
_NullSession = NullSession
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue