迎接大家拜我之私房网站《刘江的博客和科目》:www.liujiangblog.com

一言九鼎分享Python 及Django教程以及相关的博客

交流QQ群:453131687


django支持匿名会话。它用数据存放于劳务器端,并抽象cookies的出殡和收过程。cookie包含一个会话ID而无是数码本身(除非您以的凡冲后端的cookie)。

3.3.8.1 启用会话

Django通过一个当中件来落实会话功能。要启用会话就使优先启用该中间件。
修MIDDLEWARE设置,确保在django.contrib.sessions.middleware.SessionMiddleware这一行。默认情况以新建的花色蒙它是在的。

一经您免思量用会话功能,那么当settings文件中,将SessionMiddleware从MIDDLEWARE中去除,将django.contrib.sessions从
INSTALLED_APPS中去就OK了。

3.3.8.2 配置会说话引起擎

默认情况下,django将会话数据保存于数据库内(通过采取django.contrib.sessions.models.Session模型)。当然,你也可以以数据保存在文件系统或缓存内。

1. 因数据库的对话

先在INSTALLED_APPS设置中,确保django.contrib.sessions的留存,然后运行manage.py
migrate命令在数据库内创建sessions表。

2. 冲缓存的对话

从今性质角度考虑,也许你想以基于缓存的对话。

首先,你得先安排好而的缓存,请参考3.11节查阅详细。

警告:
本地缓存不是多进程安全的,因此对于生产环境不是一个好的选择。

如若您定义来差不多独缓存,django将使用默认的大。如果您想用其他的,请以SESSION_CACHE_ALIAS参数设置为颇缓存的讳。

配备好缓存后,你得挑选简单栽保存数据的措施:

  • 一是将SESSION_ENGINE设置也”django.contrib.sessions.backends.cache”,简单的对会话进行保存。但是这种办法无是生可靠,因为当缓存数据存满时用辟部分数据,或者遇到缓存服务器又开。
  • 为多少安全保,你得用SESSION_ENGINE设置为”django.contrib.sessions.backends.cached_db”。这种方法于历次缓存的时节会同时以数据在数据库内写一份。当缓存不可用时,会话会从数据库内读取数据。

片种植方法都颇迅猛,但是首先栽简单的休养存更快有,因为它忽略了数据的持久性。如果你使用缓存+数据库的计,你同样需要按照上面小节所述对数据库进行配备。

3. 因文件之对话

将SESSION_ENGINE设置为”django.contrib.sessions.backends.file”。同时,你要查看
SESSION_FILE_PATH配置(默认根据tempfile.gettempdir()生产,就比如/tmp目录),确保您的文件存储目录,以及Web服务器对拖欠目录具有读写权限。

4. 基于cookie的会话

将SESSION_ENGINE设置为”django.contrib.sessions.backends.signed_cookies”。Django将使用加密签名工具与平安秘钥设置保存会话的数目。

注意:
建议将SESSION_COOKIE_HTTPONLY设置为True,阻止javascript对会话数据的访问。

3.3.8.3 在视图中行使会话

当会话中间件启用后,传递给视图request参数的HttpRequest对象将包含一个session属性,就比如一个字典对象同。

而可以视图的别样地方读写request.session属性,或者频繁编纂使用其。

class backends.base.SessionBase
    # 这是所有会话对象的基类,包含标准的字典方法:
    __getitem__(key)
        Example: fav_color = request.session[’fav_color’]
    __setitem__(key, value)
        Example: request.session[’fav_color’] = ’blue’
    __delitem__(key)
        Example: del request.session[’fav_color’]. 如果不存在会抛出异常
    __contains__(key)
        Example: ’fav_color’ in request.session
    get(key, default=None)
        Example: fav_color = request.session.get(’fav_color’, ’red’)
    pop(key, default=__not_given)
        Example: fav_color = request.session.pop(’fav_color’, ’blue’)
    keys()
    items()
    setdefault()
    clear()


    # 它还有下面的方法:
    flush()
        # 删除当前的会话数据和会话cookie。经常用在用户退出后,删除会话。

    set_test_cookie()
        # 设置一个测试cookie,用于探测用户浏览器是否支持cookies。由于cookie的工作机制,你只有在下次用户请求的时候才可以测试。
    test_cookie_worked()
        # 返回True或者False,取决于用户的浏览器是否接受测试cookie。你必须在之前先调用set_test_cookie()方法。
    delete_test_cookie()
        # 删除测试cookie。
    set_expiry(value)
        # 设置cookie的有效期。可以传递不同类型的参数值:
    • 如果值是一个整数,session将在对应的秒数后失效。例如request.session.set_expiry(300) 将在300秒后失效.
    • 如果值是一个datetime或者timedelta对象, 会话将在指定的日期失效
    • 如果为0,在用户关闭浏览器后失效
    • 如果为None,则将使用全局会话失效策略
    失效时间从上一次会话被修改的时刻开始计时。

    get_expiry_age()
        # 返回多少秒后失效的秒数。对于没有自定义失效时间的会话,这等同于SESSION_COOKIE_AGE.
        # 这个方法接受2个可选的关键字参数
    • modification:会话的最后修改时间(datetime对象)。默认是当前时间。
    •expiry: 会话失效信息,可以是datetime对象,也可以是int或None

    get_expiry_date()
        # 和上面的方法类似,只是返回的是日期

    get_expire_at_browser_close()
        # 返回True或False,根据用户会话是否是浏览器关闭后就结束。

    clear_expired()
        # 删除已经失效的会话数据。
    cycle_key()
        # 创建一个新的会话秘钥用于保持当前的会话数据。django.contrib.auth.login() 会调用这个方法。
1. 会话序列化

Django默认使用JSON序列化会话数据。你得在SESSION_SERIALIZER设置中自定义序列化格式,甚至写副警告说明。但是咱强烈建议你要么以JSON,尤其是因cookie的法门展开对话时。

选个例证,这里发出一个以pickle序列化会话数据的抨击场景。如果您采取的是已签的Cookie会话并且SECRET_KEY被攻击者知道了(通过另外手段),攻击者就得在对话中插一个字符串,在pickle反序列化时,可以当服务器上实施危险的代码。在因特网上是攻击技术很粗略并万分爱用。尽管Cookie会话会对数据开展签约为防范篡改,但是SECRET_KEY的泄漏也让全前功尽弃。

绑定的序列化方法

class serializers.JSONSerializer


django.core.signing中JSON序列化方法的一个打包。只可以序列化基本的数据类型。另外,JSON只支持以字符串作为键值,使用其它的色会招大

>>> # initial assignment
>>> request.session[0] = 'bar'
>>> # subsequent requests following serialization & deserialization
>>> # of session data
>>> request.session[0] # KeyError
>>> request.session['0']
'bar'

平等,无法被JSON编码的,例如非UTF8格式的字节’\xd9’一样是力不从心给保存的,它见面促成UnicodeDecodeError异常。

class serializers.PickleSerializer

支撑任意档次的python对象,但是即使如前说之,可能致远端执行代码的狐狸尾巴,如果攻击者知道了SECRET_KEY。

编纂而协调之序列化方法
公的序列化类必须分别实现dumps(self, obj)和loads(self,
data)方法,用来贯彻序列化和倒序列化会话数据字典。

2. 对话对象下建议
  • 运用普通的python字符串作为request.session字典的键值。这不是同等长硬性规则而是为好起见。
  • 盖一个下划线开始的对话字典的键被Django保留作为里用。
  • 不要就此新对象覆盖request.session,不要看还是设置它的性质。像一个python字典一样的采用它们。
3. 范例

此简单的视图设置一个has_commented变量为True在用户发表评论后。它不容许用户还发表评论。

def post_comment(request, new_comment):
    if request.session.get('has_commented', False):
        return HttpResponse("You've already commented.")
    c = comments.Comment(comment=new_comment)
    c.save()
    request.session['has_commented'] = True
    return HttpResponse('Thanks for your comment!')

脚是一个简易的用户登录视图:

def login(request):
    m = Member.objects.get(username=request.POST['username'])
    if m.password == request.POST['password']:
        request.session['member_id'] = m.id
        return HttpResponse("You're logged in.")
    else:
        return HttpResponse("Your username and password didn't match.")

脚虽然是一个退出登录的视图,与方的有关:

def logout(request):
    try:
        del request.session['member_id']
    except KeyError:
        pass
    return HttpResponse("You're logged out.")

业内的django.contrib.auth.logout()函数实际上所举行的情节比较这只要又审慎,以预防意外之数据外泄,它见面调用request.session的flush()方法。我们用这事例只是演示如何使对话对象来干活,而未是一个整体的logout()实现。

3.3.8.4 设置测试cookie

为好,Django
提供一个简约的不二法门来测试用户的浏览器是否受Cookie。只需要于一个视图中调用request.session的set_test_cookie()方法,并以紧接着的视图中调用test_cookie_worked()获取测试结果(True或False)。注意,不可知在和一个视图中调用这半只章程。

招这种划分调用的原由是cookie的干活机制。当你设置一个cookie时,你无法即时得到结果,知道浏览器发送下一个要。

每当测试后,记得使用delete_test_cookie()方法清除测试数据。
下面是一个天下无双的范例:

from django.http import HttpResponse
from django.shortcuts import render

def login(request):
    if request.method == 'POST':
        if request.session.test_cookie_worked():
            request.session.delete_test_cookie()
            return HttpResponse("You're logged in.")
        else:
            return HttpResponse("Please enable cookies and try again.")
    request.session.set_test_cookie()
    return render(request, 'foo/login_form.html')

3.8.3.5 在视图外以session

注意:
在下面的例子中,我们直接从django.contrib.sessions.backends.db中导入了SessionStore对象。在你的实际代码中,你应该采用下面的导入方法,根据SESSION_ENGINE的设置进行导入,如下所示:
>>> from importlib import import_module
>>> from django.conf import settings
>>> SessionStore = import_module(settings.SESSION_ENGINE).SessionStore

于视图外有一个API可以操作会话数据:

>>> from django.contrib.sessions.backends.db import SessionStore
>>> s = SessionStore()
>>> # stored as seconds since epoch since datetimes are not serializable in JSON.
>>> s['last_login'] = 1376587691
>>> s.create()
>>> s.session_key
'2b1189a188b44ad18c35e113ac6ceead'
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
>>> s['last_login']
1376587691

SessionStore.create()用于创造一个初的对话。save()方法用于保存一个既是的对话。create方法会调用save方法并循环直到不可开交成一个免使用的session_key。直接调用save方法为可创造一个初的对话,但在生成session_key的上有或同曾有的发生冲突。

要您利用的是django.contrib.sessions.backends.db模式,那么每一个对话其实就算是一个平凡的Django模型,你可行使普通的Django数据库API访问它。会话模型的概念在django/contrib/sessions/models.py文件里。例如:

>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
>>> s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)

专注,你待调用get_decoded()方法才会取得会说话字典,因为字典是采用编码格式保存的。如下:

>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}

3.3.8.6 何时保存会话

默认情况下,只有当会讲话字典的任何价值为指定要去的时节,Django才会将会说话内容保留及会话数据库内。

# 会话被修改
request.session['foo'] = 'bar'
# 会话被修改
del request.session['foo']
# 会话被修改
request.session['foo'] = {}
# 会话没有被修改,只是修改了request.session['foo']
request.session['foo']['bar'] = 'baz'

如理解地方最后一栽情形时有发生接触困难。我们得透过安装会话对象的modified属性值,显式地报告会话对象它既让涂改了:request.session.modified
= True

一旦改者的默认行为,将SESSION_SAVE_EVERY_REQUEST设置也True,那么每一样不善单独的要过来,Django都见面保留会说话到数据库。

留神,会话的Cookie只有以一个对话被创造或者改后才会重发送。如果SESSION_SAVE_EVERY_REQUEST也True,每个请求都见面发送cookie。

恍如地,会话Cookie的失灵部分以历次发送会话Cookie时还见面更新。

倘响应的状态码为500,则会讲话不见面让封存。

3.3.8.7 浏览器在期间会话 VS 持久会话

默认情况下,SESSION_EXPIRE_AT_BROWSER_CLOSE设置为False,也就是说cookie保存在用户之浏览器内,直到失效日期,这样用户就不用每次打开浏览器后还如更登录一糟。

相反的SESSION_EXPIRE_AT_BROWSER_CLOSE设置也True,则象征浏览器同样关闭,cookie就失效,每次重复打开浏览器,你就算得又登录。

这装置是一个大局的默认值,可以透过显式地调request.session的set_expiry()方法来掩盖,前面我们就描述了了。

注意:有些浏览器(比如Chrome)具有在关闭后重新打开浏览器,会话依然保持的功能。这会与Django的SESSION_EXPIRE_AT_BROWSER_CLOSE设置发生冲突。请一定要小心。

3.3.8.8 清除已封存的对话

乘胜用户的看,会话数据会愈加大。如果你下的凡数据库保存模式,那么django_session表的始末会日渐提高。如果你以的是文本模式,那么你的即目录外之公文数量会不停增多。

致使这个题材之由来是,如果用户手动退出登录,Django将自动删除会话数据,但是如果用户不退登录,那么相应的对话数据不会见叫删除。

Django没有提供自动清除失效会话的建制。因此,你必须自己姣好这项工作。Django提供了一个命令clearsessions用于破除会话数据,建议乃因此令设置一个周期性的机关清除机制。

不等的凡,使用缓存模式之对话不需要你清理数据,因为缓存系统协调发清理过数据的机制。使用cookie模式的对话也不需,因为数量都存在用户的浏览器内,不用您拉。

3.3.8.9 设置

此地发出一部分Django的装,用于帮助您控制会话的作为:

  • SESSION_CACHE_ALIAS
  • SESSION_COOKIE_AGE
  • SESSION_COOKIE_DOMAIN
  • SESSION_COOKIE_HTTPONLY
  • SESSION_COOKIE_NAME
  • SESSION_COOKIE_PATH
  • SESSION_COOKIE_SECURE
  • SESSION_ENGINE
  • SESSION_EXPIRE_AT_BROWSER_CLOSE
  • SESSION_FILE_PATH
  • SESSION_SAVE_EVERY_REQUEST
  • SESSION_SERIALIZER

3.3.8.10 会说话安全

一个站点下之子域名能够在呢整个域名的客户设置Cookie。如果子域名被不让信赖的用户控制,那么可能有对话安全问题。

譬如说,一个攻击者可登录good.example.com并为外的账号获得一个官的对话。如果该攻击者控制了bad.example.com域名,那么他即便可行使这域名来发送他的对话秘钥给您,因为子域名允许在*.example.com上安Cookie。当您看good.example.com时,你产生或为攻击者的位置登录,然后无意中泄漏了若的私家敏感信息(例如信用卡信息)到攻击者的账号中。攻击者自然就是得了这些信息。

除此以外一个恐的攻击是,如果good.example.com设置它的SESSION_COOKIE_DOMAIN为”.example.com”
,这或引致来该站点的会话Cookie被发送到bad.example.com。

3.3.8.11 技术细节

  • 会见说话字典接收任意的json序列化值,或者其他可通过pickle序列化的python对象
  • 对话数据让保存于同摆称吧django_session的表内
  • Django
    只发送它需要的Cookie。如果您没有装任何会话数据,它不会见发送任何Cookie

SessionStore对象

在对话内部,Django使用一个在场话引擎对应之对话保存对象。根据管理,这个会话保存对象命名吧SessionStore,位于SESSION_ENGINE设置指定的模块内。

拥有Django支持之SessionStore类都蝉联SessionBase类,并落实了脚的数码操作方法:

  • exists()
  • create()
  • save()
  • delete()
  • load()
  • clear_expored()

以创造一个自定义会说话引起擎或涂改一个备的发动机,你或许需要创造一个初的类,它继续SessionBase类或另其它都存在的SessionStore类。

3.3.8.12 扩展基于数据库的对话引擎

Django 1.9版后才有职能。

设创建一个自定义的根据数据库的对话引擎,需要后续AbstractBaseSession类或者SessionStore类。

AbstractBaseSession和BaseSessionManager可以从django.contrib.sessions.base_session内导入,因此无必然不要是当INSTALLED_APPS中包含django.contrib.sessions。

class base_session.AbstractBaseSession  # 抽象会话基类
    session_key
        主键。最多40个字符。目前是一个32为随机数字或字母组合字符串。
    session_data
        一个包含了编码过的的或序列化过的会话字典的字符串
    expire_date
        失效日期
    get_session_store_class()
        这是一个类方法。返回一个会话保存类。
    get_decoded()
        返回解码后的会话数据。通过会话保存类进行解码。

乃也可以从定义模型管理器,通过编制一个BaseSessionManager的子类。

class base_session.BaseSessionManager
    encode(session_dict)
        通过会话保存类,将会话字典序列化或编码成一个字符串
    save(session_key, session_dict, expire_date)
        根据一个提供的session秘钥保存会话数据,或者删除一个空的会话

透过重复写下面这些SessionStore类的计和性,可以开展打定制:

class backends.db.SessionStore
    实现基于数据库的会话保存
    get_model_class()
        这是一个类方法。如果有需要,重写这个方法并返回一个自定义的会话模型。
    create_model_instance(data)
        返回一个会话模型对象的新实例,它代表当前会话的状态。重写这个方法,你将获得在它被保存之前,修改会话模型数据的能力。

class backends.cached_db.SessionStore
    实现基于缓存和数据库的会话保存
    cache_key_prefix
        在会话秘钥前添加一个前缀,用于构造缓存键值字符串。

范例

下面的例子展示一个自定义的冲数据库的对话引擎,包括一个格外的数据列用于储存用户之ID。

from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.contrib.sessions.base_session import AbstractBaseSession
from django.db import models

class CustomSession(AbstractBaseSession):
    account_id = models.IntegerField(null=True, db_index=True)

    @classmethod
    def get_session_store_class(cls):
        return SessionStore

class SessionStore(DBStore):
    @classmethod
    def get_model_class(cls):
        return CustomSession

    def create_model_instance(self, data):
        obj = super(SessionStore, self).create_model_instance(data)
        try:
            account_id = int(data.get('_auth_user_id'))
        except (ValueError, TypeError):
            account_id = None
        obj.account_id = account_id
        return obj

若是你是透过自Django内置的cached_db会话保存迁移到由定义之cached_db,你该再次写缓存键值的前缀,以戒命名空间的冲,如下所示:

class SessionStore(CachedDBStore):
    cache_key_prefix = 'mysessions.custom_cached_db_backend'
    # ...

3.3.8.13 URLs中之会话IDs

Django的对话框架完全地、唯一地基于Cookie。它不像PHP一样,把会话的ID放在URL中。它不仅仅使得URL变得丑陋,还教你的网站容易被通过”Referer”头部进行窃取会话ID的口诛笔伐。

相关文章

网站地图xml地图