众所周知,HTTP是一个无状态协议,为了提高效率,比较原始的方法就是引入cookies的概念(虽然现在去cookies化是大趋势,但一时半会还是要使用cookies的。)
从原理上来说,cookies就是保存在浏览器上的键值对,服务器控制这响应 ,在响应中可以让浏览器在本地保存这个键值对,下一次请求在发送的时候就会自动携带这个键值对(cookies值)。要注意的是cookies是服务端设置的,我们可以设置浏览器让服务端禁用cookies。但是有很多Web在登录的时候还是基于cookies的
cookies的作用
1.保持登录状态(几天内免登陆)
2.记录用户的浏览器习惯(搜索记录)
3.简单的防止刷票
在前面的登录案例中,我们都是不保持状态的,每次打开login页面都要登录,正常的视图函数是这样的
def login(request): if request.method == ‘POST‘: user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) if user == ‘hehe‘ and pwd ==‘123‘: return redirect(‘/home/‘) return render(request,‘login.html‘)
我们每次在打开登录页面,在POST用户名和密码以后,都会进行一次登录操作。如果登录成功,就直接跳转到下一步操作,但是每次进入login页面都要进行一次登录。
引入cookies
引入cookies的方法也比较简单,我们先看一看是怎么在程序中加载cookies的
def login(request): if request.method == ‘POST‘: user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) if user == ‘hehe‘ and pwd ==‘123‘: rep = redirect(‘/home/‘) #得到一个响应对象 rep.set_cookie(‘123‘,‘abc‘) #设置cookies return rep return render(request,‘login.html‘)
在上面的这段代码中,我们再生成一个相应对象以后对这个对象添加一个cookies以后,直接返回对象。在登录进入主页以后,重新刷新一遍,我们检查一下页面(Network)
检查一下cookies,是不是多了一个键值对,key和value就是我们在代码中添加的。
cookies的获取
再次进入home页面以后,我们可以在获取COOKIES
def home(request): ret = request.COOKIES[‘123‘] print(ret) return render(request,‘home.html‘)
然后可以对COOKIES进行比较如果,来判定是否已经登录
COOKIES的保存时间
默认情况下COOKIES的保存时间是随着浏览器的,浏览器一旦关闭COOKIES就失效。
登录时的COOKIES
我们可以把COOKIES的键值对设置成{‘is_loged‘:0},然后在登录主页的时候获取这个COOKIES,然后进行比对,如果比对成功,直接进入主页,否则跳转至登录页面。
def login(request): if request.method == ‘POST‘: user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) if user == ‘hehe‘ and pwd ==‘123‘: rep = redirect(‘/home/‘) #得到一个响应对象 rep.set_cookie(‘is_loged‘,‘1‘) #设置cookies return rep return render(request,‘login.html‘) def home(request): ret = request.COOKIES.get(‘is_loged‘,0) #获取COOKIES if ret == ‘1‘: return render(request,‘home.html‘) else: return redirect(‘/login/‘)
这样就实现了免登陆的效果。
在平时我们访问网站的时候,比方上淘宝,在每个页面都是有登录状态的,我们就要在每个页面添加一个登录校验的过程,可是有些页面是已经使用了,那么就到了装饰器的使用时间了。先看一下代码
#定义装饰器函数 def login_check(func): @wraps(func) #装饰器修复技术 def inner(request,*args,**kwargs): ret = request.COOKIES.get(‘is_logged‘,0) if ret == ‘1‘: return func(request,*args,**kwargs) else: return redirect(‘/login/‘) return inner def login(request): if request.method == ‘POST‘: user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) if user == ‘hehe‘ and pwd ==‘123‘: rep = redirect(‘/home/‘) #得到一个响应对象 rep.set_cookie(‘is_logged‘,‘1‘,max_age=10) #设置cookies return rep return render(request,‘login.html‘) #用装饰器来修饰页面判定登录情况 @login_check def home(request): return render(request,‘home.html‘)
上面这段程序的流程就是在对home页面发出请求的时候,通过装饰器函数login_check检查cookies里的登录状态,如果已经登录,就进入home页面,否则就进入登录的页面。等待登录。但是这种用法有个问题所以不大常用:如果有好多个页面在请求的时候倒要进行判定,在每个视图函数前面都要加个这个装饰器。那就要用到后面会讲到的中间件。
从Cookie到Session
虽然我们用Cookie在一定成都上解决了Http请求保持状态的需求,但是Cookie本身最大只能支持4096字节,并且由于Cookie是保存在浏览器里的,即便是用了加密盐,也很有可能被拦截或窃取,安全性很难保证。
于是,一种新的方案就出来了,我们给浏览器的Cookie分配一个唯一的id,用户在访问的时候,通过Cookie里的id从服务端取到保存了某段时间内的用户私密资料,比方登录状态,账号密码等。这样,几乎所有的数据都是存在服务器端,就没有数据大小的限制,并且由于数据是存放在服务器里,安全也相对来说高一些。
Session的优缺点
优点:
比Cookie存档数据多
安全性好
缺点
Session的数据量大,会占用一些服务器的资源,并且在请求量大时加大了服务器的负载。
Django内Session的相关方法
在Django内,Session的工作也就是下面几条:
在服务端生成一个随机的字符串
生成的随机字符串作为Cookie返回给浏览器
并且Session是在settings里绑定的数据库中的,我们可以查一下
上面的数据就是新添加 了一条Session内容以后数据库的数据。session_key就是Cookie里存储的那个随机的字符串
而那个前面说的大字典就是以密文的方式保存在session_data字段里的数据。但是有一点要注意,这个数据是只要有一个浏览器的请求一个session,过来,就会生成一个。你开两个页面就会有两条内容
获取、设置、删除Session内的数据
request.session[‘key‘] = value #设置session中的键值对 request.session[‘key‘] #获取session中的key对应的value request.session.flush() #删除当前会话并删除会话中的Cookie
我们从下面一个登录、浏览主页和注销的页面来演示一下session是怎么使用的。
def login(request): if request.method == ‘POST‘: name = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) if name == ‘aaa‘ and pwd ==‘bbb‘: rep = HttpResponse(‘登录成功‘) request.session[‘is_log‘] = 1 #session中添加登录状态 request.session[‘user‘] = name #session中添加内容 request.session.set_expiry(10) # 10秒钟之后失效 return rep else: return redirect(‘/session_test/login‘) else: return render(request,‘login.html‘) #浏览主页并检查登录状态 def home(request): print(request.session.get(‘is_log‘)) if request.session.get(‘is_log‘) == 1: return render(request,‘home.html‘) else: return redirect(‘/session_test/login‘) #注销然后进入登录页面 def clear_session(request): request.session.flush() return redirect(‘/session_test/login‘)
所有的键值对
request.sesssion.keys() --> <class ‘dict_keys‘> #获取session内所有key request.session.values() --> <class ‘dict_values‘> #获取session内所有values request.session.values() --><class ‘dict_items‘> #获取session键值对 #打印的结果dict_items([(‘is_log‘, 1), (‘user‘, ‘aaa‘), (‘_session_expiry‘, 100)]) <class ‘dict_items‘>
session中生成的随机字符串
request.session.session_key
注意这不是个方法,不用带括号。
session的清除
删除当前用户的所有Session数据
request.session.delete(‘session_key‘)#删除session_key对应的session内数据,但是只会删除session,但是Cookie里的随机字符串还在 request.session.flush() #删除session和Cookie request.session.clear_expired() #删除所有session失效日期小于当前日期的数据 request.session.set_expiry(value) #session的失效策略 #默认的过期时间是两周,如果自己设置了过期时间,这样自己设定的优先级就会高于默认的 #如果value是个整数,session会在些秒数后失效。 #如果value是个datatime或timedelta,session就会在这个时间后失效。 #如果value是0,用户关闭浏览器session就会失效。 #如果value是None,session会依赖全局session失效策略。
那个clear_expired()常常用来定时清除过期的Session来释放空间。
session的失效策略是通过Cookie的失效来实现的,如果超过指定时间,Cookie就不在存储那个随机字符串,但是Session大字典的内容是还在数据库中,必须手动调用上面那条指令来释放。
Session在settings内的设置
session还可以通过下面的内容进行设置,直接加载settings.py文件后面就行了
1. 数据库Session SESSION_ENGINE = ‘django.contrib.sessions.backends.db‘ # 引擎(默认) 2. 缓存Session SESSION_ENGINE = ‘django.contrib.sessions.backends.cache‘ # 引擎 SESSION_CACHE_ALIAS = ‘default‘ # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 3. 文件Session SESSION_ENGINE = ‘django.contrib.sessions.backends.file‘ # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 4. 缓存+数据库 SESSION_ENGINE = ‘django.contrib.sessions.backends.cached_db‘ # 引擎 5. 加密Cookie Session SESSION_ENGINE = ‘django.contrib.sessions.backends.signed_cookies‘ # 引擎 其他公用设置项: 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,默认修改之后才保存(默认)
装饰器版的Session使用
最后看一下装饰器版的Session是怎么使用的,和Cookie一样,用一个页面的请求来判定登录状态
from functools import wraps #检查登录状态的装饰器 def check_login(func): @wraps(func) def inner(request,*args,**kwargs): ret = request.session.get(‘is_log‘) if ret == 1: return func(request,*args,**kwargs) else: return redirect(‘/session_test/login/‘) return inner def login(request): return HttpResponse(12345656) def login(request): if request.method == ‘POST‘: name = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) if name == ‘aaa‘ and pwd ==‘bbb‘: rep = HttpResponse(‘登录成功‘) request.session[‘is_log‘] = 1 #session中添加登录状态 request.session[‘user‘] = name #session中添加内容 request.session.set_expiry(100) # 10秒钟之后失效 return rep else: return redirect(‘/session_test/login‘) else: return render(request,‘login.html‘) #用装饰器检查登录状态 @check_login def home(request): return render(request,‘home.html‘)
Django学习笔记一十五——cookies和session
原文:https://www.cnblogs.com/yinsedeyinse/p/12799403.html