`
san_yun
  • 浏览: 2662751 次
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

django session实现

 
阅读更多

django的session是通过SessionMiddleware实现的。

 

import time

from django.conf import settings
from django.utils.cache import patch_vary_headers
from django.utils.http import cookie_date
from django.utils.importlib import import_module

class 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 base64
import os
import random
import sys
import time
from datetime import datetime, timedelta
try:
    import cPickle as pickle
except ImportError:
    import pickle

from django.conf import settings
from django.core.exceptions import SuspiciousOperation
from django.utils.hashcompat import md5_constructor
from 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().randrange
else:
    randrange = random.randrange
MAX_SESSION_KEY = 18446744073709551616L     # 2 << 63

class CreateError(Exception):
    """
    Used internally as a consistent exception type to catch from save (see the
    docstring for SessionBase.save() for details).
    """
    pass

class 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_user


class 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)

 

 

分享到:
评论

相关推荐

    Django Session和Cookie分别实现记住用户登录状态操作

    在Django框架中,有两种主要方法可以实现这一功能:Django Session和Cookie。理解这两者的工作原理和如何在Django中使用它们至关重要。 首先,让我们深入了解Cookie。Cookie是由服务器发送到用户浏览器的一小段数据...

    Django实现登录-注册等功能

    9. **会话管理(Session Management)**: Django使用会话来跟踪用户的登录状态。默认情况下,会话数据存储在cookie中,但你可以选择其他存储方式,如数据库或缓存。 10. **密码重置(Password Reset)**: Django还提供...

    django session完成状态保持的方法

    本文将详细介绍如何利用 Django 的 Session 功能来实现状态保持,并通过一个具体的示例——登录页面来演示 Session 的工作原理。 #### 二、状态保持的概念及重要性 1. **状态保持的目的**:状态保持的主要目标是在...

    Python Django实现简单购物车功能

    在本文中,我们将深入探讨如何使用Python的Django框架实现一个简单的购物车功能。Django是一个强大且高效的Web开发框架,它提供了丰富的功能和工具,使得构建电子商务网站变得更加容易。 首先,我们需要创建一个新...

    django-利用session机制实现唯一登录的例子

    session_data = DjangoSession.objects.filter(session_key=key).values_list('session_data')[0][0] # 删除key不为当前key,session_data等于当前session_data的session记录 DjangoSession.objects.filter(session...

    Python库 | django-session-idle-timeout-1.3.0.tar.gz

    1. **配置灵活性**:开发者可以自定义会话闲置多久后超时,这通过设置`SESSION_IDLE_TIMEOUT`配置项实现。这样,根据不同的业务需求,可以选择合适的超时时间,如5分钟、1小时等。 2. **中间件集成**:库提供了...

    云端留言板 django实现

    【云端留言板 django实现】 在IT领域,Web开发是不可或缺的一部分,而Django作为一个高效、免费且开源的Python Web框架,因其强大的功能和易用性深受开发者喜爱。本项目以“云端留言板”为例,展示了如何利用Django...

    Python Django简单实现session登录注销过程详解

    本文将详细介绍如何使用Django的Session功能实现简单的登录和注销过程。首先,我们要了解Django中的Session是如何工作的。 Session是服务器端存储用户状态的一种方式,通常与Cookie配合使用。当用户访问网站并登录...

    django之session与分页(实例讲解)

    在Django中,可以使用`django.core.paginator`模块实现高效且易于使用的分页。以下是一个简单的分页视图示例: ```python from django.shortcuts import render, HttpResponse from django.core.paginator import ...

    Django_ORM.zip_Oldboy 3_django_django orm_orm_session

    "django_orm"是Django中的一个重要组成部分,它实现了ORM系统。ORM使得开发者可以将数据库操作与业务逻辑分离,通过Python类定义模型,模型对应数据库表,模型实例则对应表中的记录。在Django中,ORM支持多种数据库...

    Django框架实现简单电影小网站

    4. 用户退出:用户退出功能是通过注销视图实现的,该视图会清除用户的session数据,使用户状态回到未登录。 5. 收藏功能:收藏功能需要我们创建一个模型来存储用户收藏的电影信息,通常包括用户ID和电影ID。在视图...

    Go-DjangoWeb框架的Curl对Django服务器进行身份验证请求

    在开发Web应用时,Go语言和Django框架的...总之,结合Go语言的Curl工具和Django框架,开发者可以轻松地测试和实现Web服务的身份验证和OAuth授权。通过理解这些基本概念和技术,你可以创建更安全、更可扩展的Web应用。

    Django中使用session保持用户登陆连接的例子

    Django作为一款流行的Python Web框架,提供了一套内建的Session框架来帮助开发者实现用户的登录保持。Session框架在用户登录后在服务器端生成一个唯一的会话标识(session key),然后将其作为cookie存储在用户的...

    Django cookie 与 session

    本文将深入探讨Django中的Cookie与Session,以及如何在实际应用中使用它们。 首先,Cookie是存储在客户端(用户浏览器)上的小数据块,通常用于存储用户的一些非敏感信息,如会话ID或者用户偏好。当用户访问网站时...

    Django1.6_利用Form实现注册登录注销修改密码

    登录功能通常使用Django内置的`AuthenticationForm`,并结合`login`视图来实现: ```python from django.contrib.auth import authenticate, login from django.contrib.auth.forms import AuthenticationForm from...

    Django框架自定义session处理操作示例

    本文将深入探讨 Django 中自定义 Session 的实现方法及其应用场景。 #### 二、Session 原理及作用 在介绍自定义 Session 之前,首先需要了解 Session 的基本概念和原理: - **Session 概念**:Session 是一种服务器...

    django rest framework vue 实现用户登录详解

    在Django REST framework中实现用户登录,需要在Django的视图(views.py)中编写API接口,通常使用TokenAuthentication或SessionAuthentication这两种认证方式。 #### TokenAuthentication 使用TokenAuthentication...

    Python开发工程师学会用 Django 框架实现功能Ns 的用户.zip

    8. **Session和Cookie管理**:Django的session机制用于在服务器端存储用户会话信息,而cookie则在客户端保存用户状态。它们协同工作,实现用户的登录状态维持。 9. **中间件**:Django的中间件可以全局影响请求和...

Global site tag (gtag.js) - Google Analytics