首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

django session兑现

2013-04-20 
django session实现import timefrom django.conf import settingsfrom django.utils.cache import patch_v

django session实现
import timefrom django.conf import settingsfrom django.utils.cache import patch_vary_headersfrom django.utils.http import cookie_datefrom django.utils.importlib import import_moduleclass SessionMiddleware(object): def process_request(self, request): engine = import_module(settings.SESSION_ENGINE) session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None) request.session = engine.SessionStore(session_key) def process_response(self, request, response): """ If request.session was modified, or if the configuration is to save the session every time, save the changes and set a session cookie. """ try: accessed = request.session.accessed modified = request.session.modified except AttributeError: pass else: if accessed: patch_vary_headers(response, ('Cookie',)) if modified or settings.SESSION_SAVE_EVERY_REQUEST: if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = cookie_date(expires_time) # Save the session data and refresh the client cookie. request.session.save() response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None) return response

其中重点是

engine.SessionStore(session_key)

django提供了SessionBase以供扩展

import base64import osimport randomimport sysimport timefrom datetime import datetime, timedeltatry:    import cPickle as pickleexcept ImportError:    import picklefrom django.conf import settingsfrom django.core.exceptions import SuspiciousOperationfrom django.utils.hashcompat import md5_constructorfrom django.utils.crypto import constant_time_compare, salted_hmac# Use the system (hardware-based) random number generator if it exists.if hasattr(random, 'SystemRandom'):    randrange = random.SystemRandom().randrangeelse:    randrange = random.randrangeMAX_SESSION_KEY = 18446744073709551616L     # 2 << 63class CreateError(Exception):    """    Used internally as a consistent exception type to catch from save (see the    docstring for SessionBase.save() for details).    """    passclass SessionBase(object):    """    Base class for all Session classes.    """    TEST_COOKIE_NAME = 'testcookie'    TEST_COOKIE_VALUE = 'worked'    def __init__(self, session_key=None):        self._session_key = session_key        self.accessed = False        self.modified = False    def __contains__(self, key):        return key in self._session    def __getitem__(self, key):        return self._session[key]    def __setitem__(self, key, value):        self._session[key] = value        self.modified = True    def __delitem__(self, key):        del self._session[key]        self.modified = True    def keys(self):        return self._session.keys()    def items(self):        return self._session.items()    def get(self, key, default=None):        return self._session.get(key, default)    def pop(self, key, *args):        self.modified = self.modified or key in self._session        return self._session.pop(key, *args)    def setdefault(self, key, value):        if key in self._session:            return self._session[key]        else:            self.modified = True            self._session[key] = value            return value    def set_test_cookie(self):        self[self.TEST_COOKIE_NAME] = self.TEST_COOKIE_VALUE    def test_cookie_worked(self):        return self.get(self.TEST_COOKIE_NAME) == self.TEST_COOKIE_VALUE    def delete_test_cookie(self):        del self[self.TEST_COOKIE_NAME]    def _hash(self, value):        key_salt = "django.contrib.sessions" + self.__class__.__name__        return salted_hmac(key_salt, value).hexdigest()    def encode(self, session_dict):        "Returns the given session dictionary pickled and encoded as a string."        pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)        hash = self._hash(pickled)        return base64.encodestring(hash + ":" + pickled)    def decode(self, session_data):        encoded_data = base64.decodestring(session_data)        try:            # could produce ValueError if there is no ':'            hash, pickled = encoded_data.split(':', 1)            expected_hash = self._hash(pickled)            if not constant_time_compare(hash, expected_hash):                raise SuspiciousOperation("Session data corrupted")            else:                return pickle.loads(pickled)        except Exception:            # ValueError, SuspiciousOperation, unpickling exceptions            # Fall back to Django 1.2 method            # PendingDeprecationWarning <- here to remind us to            # remove this fallback in Django 1.5            try:                return self._decode_old(session_data)            except Exception:                # Unpickling can cause a variety of exceptions. If something happens,                # just return an empty dictionary (an empty session).                return {}    def _decode_old(self, session_data):        encoded_data = base64.decodestring(session_data)        pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]        if not constant_time_compare(md5_constructor(pickled + settings.SECRET_KEY).hexdigest(),                                     tamper_check):            raise SuspiciousOperation("User tampered with session cookie.")        return pickle.loads(pickled)    def update(self, dict_):        self._session.update(dict_)        self.modified = True    def has_key(self, key):        return self._session.has_key(key)    def values(self):        return self._session.values()    def iterkeys(self):        return self._session.iterkeys()    def itervalues(self):        return self._session.itervalues()    def iteritems(self):        return self._session.iteritems()    def clear(self):        # To avoid unnecessary persistent storage accesses, we set up the        # internals directly (loading data wastes time, since we are going to        # set it to an empty dict anyway).        self._session_cache = {}        self.accessed = True        self.modified = True    def _get_new_session_key(self):        "Returns session key that isn't being used."        # The random module is seeded when this Apache child is created.        # Use settings.SECRET_KEY as added salt.        try:            pid = os.getpid()        except AttributeError:            # No getpid() in Jython, for example            pid = 1        while 1:            session_key = md5_constructor("%s%s%s%s"                    % (randrange(0, MAX_SESSION_KEY), pid, time.time(),                       settings.SECRET_KEY)).hexdigest()            if not self.exists(session_key):                break        return session_key    def _get_session_key(self):        if self._session_key:            return self._session_key        else:            self._session_key = self._get_new_session_key()            return self._session_key    def _set_session_key(self, session_key):        self._session_key = session_key    session_key = property(_get_session_key, _set_session_key)    def _get_session(self, no_load=False):        """        Lazily loads session from storage (unless "no_load" is True, when only        an empty dict is stored) and stores it in the current instance.        """        self.accessed = True        try:            return self._session_cache        except AttributeError:            if self._session_key is None or no_load:                self._session_cache = {}            else:                self._session_cache = self.load()        return self._session_cache    _session = property(_get_session)    def get_expiry_age(self):        """Get the number of seconds until the session expires."""        expiry = self.get('_session_expiry')        if not expiry:   # Checks both None and 0 cases            return settings.SESSION_COOKIE_AGE        if not isinstance(expiry, datetime):            return expiry        delta = expiry - datetime.now()        return delta.days * 86400 + delta.seconds    def get_expiry_date(self):        """Get session the expiry date (as a datetime object)."""        expiry = self.get('_session_expiry')        if isinstance(expiry, datetime):            return expiry        if not expiry:   # Checks both None and 0 cases            expiry = settings.SESSION_COOKIE_AGE        return datetime.now() + timedelta(seconds=expiry)    def set_expiry(self, value):        """        Sets a custom expiration for the session. ``value`` can be an integer,        a Python ``datetime`` or ``timedelta`` object or ``None``.        If ``value`` is an integer, the session will expire after that many        seconds of inactivity. If set to ``0`` then the session will expire on        browser close.        If ``value`` is a ``datetime`` or ``timedelta`` object, the session        will expire at that specific future time.        If ``value`` is ``None``, the session uses the global session expiry        policy.        """        if value is None:            # Remove any custom expiration for this session.            try:                del self['_session_expiry']            except KeyError:                pass            return        if isinstance(value, timedelta):            value = datetime.now() + value        self['_session_expiry'] = value    def get_expire_at_browser_close(self):        """        Returns ``True`` if the session is set to expire when the browser        closes, and ``False`` if there's an expiry date. Use        ``get_expiry_date()`` or ``get_expiry_age()`` to find the actual expiry        date/age, if there is one.        """        if self.get('_session_expiry') is None:            return settings.SESSION_EXPIRE_AT_BROWSER_CLOSE        return self.get('_session_expiry') == 0    def flush(self):        """        Removes the current session data from the database and regenerates the        key.        """        self.clear()        self.delete()        self.create()    def cycle_key(self):        """        Creates a new session key, whilst retaining the current session data.        """        data = self._session_cache        key = self.session_key        self.create()        self._session_cache = data        self.delete(key)    # Methods that child classes must implement.    def exists(self, session_key):        """        Returns True if the given session_key already exists.        """        raise NotImplementedError    def create(self):        """        Creates a new session instance. Guaranteed to create a new object with        a unique key and will have saved the result once (with empty data)        before the method returns.        """        raise NotImplementedError    def save(self, must_create=False):        """        Saves the session data. If 'must_create' is True, a new session object        is created (otherwise a CreateError exception is raised). Otherwise,        save() can update an existing object with the same key.        """        raise NotImplementedError    def delete(self, session_key=None):        """        Deletes the session data under this key. If the key is None, the        current session key value is used.        """        raise NotImplementedError    def load(self):        """        Loads the session data and returns a dictionary.        """        raise NotImplementedError

?

AuthUser同样是通过Middleware实现

auth:

def get_user(request):    from django.contrib.auth.models import AnonymousUser    try:        user_id = request.session[SESSION_KEY]        backend_path = request.session[BACKEND_SESSION_KEY]        backend = load_backend(backend_path)        user = backend.get_user(user_id) or AnonymousUser()    except KeyError:        user = AnonymousUser()    return user

?LazyUser

class LazyUser(object):    def __get__(self, request, obj_type=None):        if not hasattr(request, '_cached_user'):            from django.contrib.auth import get_user            request._cached_user = get_user(request)        return request._cached_userclass AuthenticationMiddleware(object):    def process_request(self, request):        assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."        request.__class__.user = LazyUser()        return None

?

?

session的执行流程

1. user_id = request.session[SESSION_KEY]2. class SessionBase(object):    def __getitem__(self, key):        return self._session[key]3.class SessionBase(object): def _get_session(self, no_load=False):        """        Lazily loads session from storage (unless "no_load" is True, when only        an empty dict is stored) and stores it in the current instance.        """        self.accessed = True        try:            return self._session_cache        except AttributeError:            if self._session_key is None or no_load:                self._session_cache = {}            else:                self._session_cache = self.load()        return self._session_cache    _session = property(_get_session)

?

?

热点排行