简介
早起的web应用都相对简单,只是简单的展示内容,无需记录用户的状态信息(例如登录状态等),后面随着web应用的发展web应用出现了获取用户状态信息等需求。
以用户登录状态为例,博客的收藏文档需要登录认证才会展现用户自己的收藏文档,那么就需要用户输入账号密码,但是频繁的输入账号密码会影响用户的体验,因此诞生了一次认证,多次使用的需求。
解决思路大体是服务端认证成功后,随机生成字符串,交给浏览器;之后浏览器访问都带上这个字符串交由服务端认证,认证通过则判定为已登录状态,无需多次输入账号密码。
cookie和session就是具体的解决方案
cookie
服务端保存在客户端浏览器上的信息,其表现形式一般是键值对(可以多个)
session
服务端保存在服务端的信息,其表现形式也是键值对。
session 与 cookie 的区别
session 在服务器端,cookie 在客户端。
session 用户无法查看和修改,cookie 用户可以查看修改。
session 和 cookie 的存储容量不同。
session 的实现依赖于 sessionID,而 sessionID 又存储在 cookie 上,所以,可以这么说:session 是基于 cookie 实现的一种数据存储方式。
Cookie使用
cookie虽然是服务端告知浏览器的需要保存的信息,但浏览器也可以拒绝保存,不过这样会导致利用cookie的网页都将无法正常工作,例如无法记录用户的登录状态
cookie的设置
django的视图函数,其返回值都是基类HttpResponseBase的对象,该对象存在设置cookie的方法:set_cookie(),通过该方法我们可以为django 的每一次返回都附件cookie信息。
在设置cookie的时候可以添加一个超时时间
obj.set_cookie(‘username’, ‘jason666’,max_age=3,expires=3)
max_age
expires
两者都是设置超时时间的 并且都是以秒为单位
需要注意的是 针对IE浏览器必需使用expires
过期的cookie将会被浏览器清除
cookie的获取
浏览器保存cookie后,每次访问服务端都会带上cookie,django后端可以通过request.COOKIES.get(key)获取浏览器传来的cookie。依次进行认证。
cookie的删除
obj.delete_cookie(key),多用于类似退出登录这样的场景
cookie的应用实例
需求:
设计一个web系统该系统有一个登录页面和若干个业务页面。
只有在登录认证过的状态下才能访问业务页面,否则都跳转到登陆页面。
跳转到登录并认证通过后,就能跳转到之前欲访问的目标页面。
登录页面文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>请登录</h1>
<form action="" method="post">
用户<input type="text" name="username">
密码<input type="text" name="passwd">
<input type="submit">
</form>
</body>
</html>
视图层代码:
from django.shortcuts import render,HttpResponse,redirect
# Create your views here.
def login_auth(func):
def inner(request,*args,**kwargs):
cookie=request.COOKIES.get('panks')
if cookie:
return func(request)
else:
print(request.get_full_path_info())
dest=request.get_full_path_info()
return redirect('/login?next=%s'%dest)
return inner
def login(request):
if request.method=='POST':
username=request.POST.get('username')
passwd = request.POST.get('passwd')
if username=='panks' and passwd=='321':
dest=request.GET.get('next')
if dest:
obj=redirect(dest)
else:
obj=redirect('/home')
obj.set_cookie('panks','321')
return obj
return render(request, 'app01/login.html')
@login_auth
def index(request):
return HttpResponse('这里是首页')
@login_auth
def home(request):
return HttpResponse('这里是家目录')
上诉例子主要为了演示效果,实现对cookie认证来通过用户的登录认证,标记用户的状态为已登记,而对于cookie是认证没有太严谨。
实际项目中可以随机生成字符串代替上面的‘321’来设置cookie,并在cookie存储在redis等第三方数据库中,在执行login_auth时,可以从redis中取出原值对客户端提交的cookie进行校验。
session使用
session数据是保存在服务端的(在django框架中默认保存在数据库中)
返回给客户端的是一个随机字符串,客户端该随机字符串在服务端中以为session_key为键存储。
session的作用和cookie类似,用于分辨发起本次请求的用户状态。
在默认情况下django会自动创建django_session用于记录session数据,该表有三个字段:
session_key
服务端针对(没有带cookie或者cookie所对应的session已经过期又或者cookie查找不到对应session)的请求生成的一个随机字符串座位session_key,并以sessionid为键以该随机字符串为值组成一个cookie交给客户端;
session_data
暂时理解为后端设置的session键值对加密后的所得的字符串
expire_date
表示该session数据的过期时间,django默认session的过期时间是14天,但是你也可以人为的修改它
设置session
request.session[‘key’] = value
django内部流程:
- django内部生成一个随机字符串,名为session_key也可以叫sessionid
- django内部将随机字符串和对应的数据(session设置的键值对加密后得到)存储到django_session表中
2.1先在内存中产生操作数据的缓存
2.2在准备响应结果时,django中间件将session数据写入操作数据库 - 将产生的随机字符串返回给客户端浏览器以cookie的形式保存
获取session
request.session.get(‘key’)
django内部流程:
- 自动从浏览器请求中获取sessionid对应的随机字符串
- 拿着该随机字符串去django_session表中查找对应的数据(条件为sessionid=session_key)
- 如果比对上了 则将对应的session_data数据取出并以字典的形式封装到request.session中,通过request.session.get()取出值
如果比对不上 则request.session.get()默认返回的是None
设置过期时间
request.session.set_expiry(),括号内可以放四种类型的参数:
1. 整数 多少秒
2. 日期对象 到指定日期就失效
3. 0 一旦当前浏览器窗口关闭立刻失效
4. 不写 失效时间就取决于django内部全局session默认的失效时间
清除session
request.session.delete() # 只删服务端的 客户端的不删
request.session.flush() # 浏览器和服务端都清空(推荐使用)
session是保存在服务端的 但是session的保存位置可以有多种选择
1.MySQL
2.文件
3.redis
4.memcache
…
一个计算机上(IP地址)的一个浏览器只会有一条session数据生效
当session过期的时候可能会出现多条数据对应一个浏览器,但是该现象不会持续很久,内部会自动识别过期的数据清除 你也可以通过代码清除,主要是为了节省服务端数据库资源
session的应用示例
利用session机制重写cookie应用示例,需求不变,故前端代码无需变动,重写视图层
from django.shortcuts import render,HttpResponse,redirect
# Create your views here.
def login_auth(func):
def inner(request,*args,**kwargs):
sessionId=request.session.get('panks')
print(sessionId)
if sessionId:
return func(request)
else:
print(request.get_full_path_info())
dest=request.get_full_path_info()
return redirect('/login?next=%s'%dest)
return inner
def login(request):
if request.method=='POST':
username=request.POST.get('username')
passwd = request.POST.get('passwd')
if username=='panks' and passwd=='321':
dest=request.GET.get('next')
if dest:
obj=redirect(dest)
else:
obj=redirect('/home')
request.session['panks']=321
return obj
return render(request, 'app01/login.html')
@login_auth
def index(request):
return HttpResponse('这里是首页')
@login_auth
def home(request):
return HttpResponse('这里是家目录')