Django组件之Cookie&Session
一 会话跟踪技术
1.1 什么是会话跟踪技术
我们需要先了解一下什么是会话!可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应。例如:你给 10086 打个电话,你就是客户端,而 10086 服务人员就是服务器了。从双方接通电话那一刻起,会话就开始了,到某一方挂断电话表示会话结束。在通话过程中,你会向 10086 发出多个请求,那么这多个请求都在一个会话中。在JavaWeb 中,客户向某一服务器发出第一个请求开始,会话就开始了,直到客户关闭了浏览器会话结束。在一个会话的多个请求中共享数据,这就是会话跟踪技术。
例如在一个会话中的请求如下:请求银行主页
- 请求登录(请求参数是用户名和密码);
- 请求转账(请求参数与转账相关的数据);
- 请求信用卡还款(请求参数与还款相关的数据)
在上面的会话中当前用户信息必须在这个会话中是共享的,因为登录的是张三,那么在转账和还款时一定是相对张三的转账和还款!这就说明我们必须在一个会话过程中有共享数据的能力。
1.2 会话路径技术使用 Cookie 或 session 完成
我们知道 HTTP 协议是无状态协议,也就是说每个请求都是独立的!无法记录前一次请求的状态。但 HTTP 协议中可以使用 Cookie 来完成会话跟踪!在 Web 开发中,使用 session 来完成会话跟踪, session 底层依赖 Cookie 技术。
二 Cookie
2.1 Cookie简介
- 保存在客户端浏览器上的键值对
- 服务器可以向用户浏览器端写Cookie
- 客户端每次发送请求时,会携带Cookie到服务端
- 主要应用在用户登录验证、投票
注意:客户端浏览器不要将cookie禁止,否则服务端无法设置客户端cookie数据,导致登录异常。
2.2 Cookie规范
- Cookie 大小上限为 4KB
- 一个服务器最多在客户端浏览器上保存 20 个 Cookie
- 一个浏览器最多保存 300 个 Cookie
上面的数据只是HTTP 的 Cookie 规范,但在浏览器大战的今天,一些浏览器为了打败对手,为了展现自己的能力起见,可能对 Cookie 规范 扩展 了一些,例如每个 Cookie 的大小为 8KB ,最多可保存 500 个 Cookie 等!但也不会出现把你硬盘占满的可能!
注意:不同浏览器之间是不共享Cookie 的。也就是说在你使用 IE 访问服务器时,服务器会把 Cookie 发给 IE ,然后由IE 保存起来,当你在使用 FireFox 访问服务器时,不可能把 IE 保存的 Cookie 发送给服务器。
2.3 Cookie与HTTP头
Cookie是通过 HTTP 请求和响应头在客户端和服务器端传递的:
- Cookie :请求头,客户端发送给服务器端
- 格式: Cookie: a=A; b=B; c=C 。即多个 Cookie 用分号离开;
- Set Cookie :响应头,服务器端发送给客户端
- 一个 Cookie 对象一个 Set Cookie。Set Cookie: a=A Set Cookie: b=B Set Cookie: c=C
2.4 Cookie的覆盖
如果服务器端发送重复的 Cookie 那么会覆盖原有的 Cookie ,例如:客 户端的第一个请求服务器端发送的 Cookie 是:Set Cookie: a=A ;第二请求服务器端发送的是 Set Cookie: a=AA ,那么客户端只留下一个 Cookie ,即 a=AA 。
2.5 Cookie操作
2.5.1 设置cookie
1. 普通设置
set_cookie(self, key, value='', max_age=None, expires=None, path='/',domain=None, secure=False, httponly=False)
#key: 键
#value:值
#max_age: 超时时间(单位:秒),建议使用。内部通过expires进行设置
#expires: 超时时间(格式为datatime)
#path: 设置针对该cookie生效路径,如:'/index',只能index下能访问。默认为“/”,所有路径均生效
#domain: 设置针对该cookie生效域名,默认为当前域名
#secure: 是否通过安全的HTTPS连接来传输(https时,设为ture)
#httponly: 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
2. cookie签名(加盐)
#普通cookie是明文传输的,可以直接在客户端直接打开,所以需要加盐,解盐之后才能查看 set_signed_cookie(self, key, value, salt='', **kwargs)
2.5.2 获取cookie
1. 普通获取
request.COOKIES.get('Cookie的key')
2. 签名获取
request.get_signed_cookie(self, key, default=RAISE_ERROR, salt='', max_age=None)
2.5.3 删除cookie
response = HttpResponse('ok') or ...
response.delete_cookie("cookie_key", path="/", domain=name)
return response
2.6 示例--用户登录验证
from django.shortcuts import render, redirect, HttpResponse import json, datetime from datetime import timedelta user_list = [ {"username":"joe1","password":"123"}, {"username":"joe2","password":"123"}, {"username":"joe3","password":"123"}, ] def login(request): '''用户登录''' if request.method == "GET": return render(request, "login.html") else: user_name = request.POST.get("username") pwd = request.POST.get("password") for user in user_list: if user_name == user["username"] and pwd == user["password"]: obj = redirect('/page1/') # 通过max_age指定超时时间 obj.set_cookie("ticket", '123456789', max_age=100) # 通过expires指定超时时间 # now_time = datetime.datetime.utcnow() # delta = timedelta(seconds=10) # time_out = now_time + delta # obj.set_cookie("ticket",'123456789', expires=time_out) # cookie签名(加密) # obj.set_signed_cookie("ticket", '123456789', salt='abcdefg', max_age=10) return obj else: return render(request, "login.html") def judge_status(func): '''用户登录状态判断''' def wrapper(request, *args, **kwargs): # 通过普通方式获取cookie cookie_value = request.COOKIES.get("ticket") # 通过加密方式获取cookie,不加try会报错,提示‘ticket’错误 # try: # cookie_value = request.get_signed_cookie('ticket',salt='abcdefg') # except Exception: # cookie_value = False if cookie_value: ret = func(request, *args, **kwargs) return ret else: return render(request, "login.html") return wrapper @judge_status def page1(request): return render(request, 'page1.html') @judge_status def page2(request): return render(request, 'page2.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="post" action="/login/"> {% csrf_token %} <p>用户名:<input type="text" name="username"></p> <p>密码:<input type="password" name="password"></p> <p><input type="submit" value="提交"></p> </form> </body> </html>
未签名cookie样式:
签名cookie样式:
补充:
由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
<script src='/static/js/jquery.cookie.js'></script>
$.cookie("list_pager_num", 30,{ path: '/' });
三 Session
3.1 Session简介
- Session:保存在服务端的数据(本质是键值对)
- 应用:依赖Cookie
- 作用:保持会话,记住用户的登录状态(WEB网站,分布式架构)
- 优点:敏感信息不会直接给客户端,防止客户端修改cookie信息
Session作用过程简图如下:
客户端Cookie:
注:如报错,先执行数据库迁移操作后再试试
python manage.py makemigrations python manage.py migrate
3.2 Django中的Sesssion
Django中默认支持Session,并且默认将session数据存储在数据库中,即:django_session表中。其内部提供了5种类型的Session供我们使用:
- 数据库(默认)
- 缓存
- 文件
- 缓存加文件
- 加密Cookie
3.2.1 数据库Session
1. 配置settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)。简单来说是否每次刷新更新失效时间
2. Session的使用
def use(request):
# 获取、设置、删除Session中数据
request.session['k1'] # 获取Session中key为‘k1’的数据,没有则报错
request.session.get('k1', None) # 获取Session中key为‘k1’的数据,没有返回None
request.session['k1'] = 123 # 设置Session中key为‘k1’的值
request.session.setdefault('k1', 123) # 设置Session中key为‘k1’的值,存在则不设置
del request.session['k1'] # 删除Session中key为‘k1’的键值对
k1 = request.session.pop('k1')
# 所有键、值、键值对
request.session.keys() # 获取Session中的key值
request.session.values() # 获取Session中的value值
request.session.items() # 获取Session中的key,value值
request.session.iterkeys() # 亲测报错,AttributeError: 'dict' object has no attribute 'iterkeys',待继续验证
request.session.itervalues() # 同上
request.session.iteritems() # 同上
# 用户随机字符串
request.session.session_key # 获取用户session的随机字符串
request.session.clear_expired() # 将所有Session失效日期小于当前日期的数据删除
request.session.exists("随机字符串") # 检查用户session的随机字符串在数据库中是否存在
request.session.delete("随机字符串") # 删除当前用户的所有Session数据
request.session.set_expiry(value)
# 如果value是个整数,session会在些秒数后失效。
# 如果value是个datatime或timedelta,session就会在这个时间后失效。
# 如果value是0,用户关闭浏览器session就会失效。
# 如果value是None,session会依赖全局session失效策略(优先级高于默认设置值)。
3.2.2 其他
采用其他方式时,只需要在settings.py中对引擎进行设置,即可改变Session类型,使用与数据库Session一致。
1. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
注意:Django缓存相关内容请参考后续博客。
2. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
3. 缓存+数据库Session
#数据库用于持久化,缓存用于提高效率 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
4. 加密cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
注:以上方式中数据库及缓存较为常用。
更多参考:
https://docs.djangoproject.com/en/1.9/topics/http/sessions/
https://docs.djangoproject.com/en/1.9/ref/settings/#settings-sessions
3.3 实例应用--用户登录验证
from django.shortcuts import render,HttpResponse,redirect def login(request): '''用户登录''' if request.method == 'GET': return render(request,'login.html') else: username = request.POST.get("username") pwd = request.POST.get("pwd") if username == 'joe1991' and pwd =='123': #实际应用中应该从数据库获取相应用户信息进行比对,这里为了简便,直接指定 # 1. 生成随机字符串 # 2. 通过cookie发送给客户端 # 3. 服务端保存{随机字符串1: {'username':'joe1991','pwd':'123'...}} request.session['username'] = username return redirect('/main/') else: return render(request, 'login.html') def main(request): ''' 1. 获取客户端端cookie中的随机字符串 2. 去session中查找有没有随机字符 3. 去session对应的随机字符串的value中的key的value中查看是否有username ''' username = request.session.get('username') if username: return HttpResponse('登录成功:%s' %username) else: return redirect('/login/')
当然,我们也可以使用装饰器:
def login_verify(func):
def wrap(request, *args, **kwargs):
# 如果未登陆,跳转到登陆页面
if not request.session.get('username'):
return redirect('/login/')
else:
return func(request, *args, **kwargs)
return wrap
记录:同一浏览器的sessionid不变,切换用户登录也一样。但不同浏览器的sessionid不同。
3.4 Session注意事项
- 每个用户的保存在服务端的sessionid是不一样的,不会造成用户间的信息混淆;
- 如果A用户和B用户在同一个浏览器登录,sessionid不变,但是服务端session中的数据会被新用户覆盖;
- 不同浏览器的sessionid不同;
- 如果cookie泄露了,其他人拿着我们的cookie也是可以 访问服务端的,所以cookie一定要保存好。
总结:因为Session的优势,建议以后使用Session。






浙公网安备 33010602011771号