Cookie和Session
原文链接:https://www.cnblogs.com/maple-shaw/articles/9502602.html
cookie 数据解码:https://jwt.io/

Cookie
首先新建一个项目:




数据库就直接用这个了:

不需要:

我们需要的实现的逻辑是登录之后之后跳转首页
设置登录页面和首页的url

登录页面如下:
1)form表单,post请求方式,是否开启csrf。用户密码输入框添加name属性,如果出错显示渲染信息的地方。以及提交表单的按钮

登录代码逻辑如下:
1)导入View类,自定义login类继承它。
2)写get和post方法,self是第一个参数,request作为第二个参数,并且接收所有的其它传参
3)get请求时直接返回login的页面
4)post请求时需要获取form表单POST中的username和pwd,并用获取的键值对内容和数据库中用户密码比对,满足相等就重定向页面到首页地址。否则返回登录页面并传用户或密码的error信息渲染到登录页面的提交上面

首页视图函数直接返回字符串:

现在随便输入用户名和密码,提交报错:

输入正确的信息正确跳转到首页


现在使用两个浏览器登录首页试试都是可以直接/index/地址访问的,而不用用户登录之后才跳转。直接访问地址就可以进入首页
但是正常的逻辑是用户登录成功之后才能跳转到首页。所以我们需要的是登录之后才跳转,没有登录的就让它重新去登录

但是现在有个问题就是,有没有登录是不知道的,对于服务器来说,登录没登录都是一样的。
如下:
1)方框是服务器,左圆是浏览器1,右圆是浏览器2
2)浏览器1先是发送一个get请求,获取到登录页面。再发送一个post请求,如果用户名和密码正确那么服务器返回一个重定向地址,然后再get首页页面,服务器返回首页页面
3)浏览器2直接访问index地址,get拿到index页面
4)我们需要实现的是浏览器1这种登录了的可以拿到页面;浏览器2这种没有登录的是不能拿到页面,应该让它登录以后再拿到这个页面,
5)现在的情况是这两种方法都能访问到index页面,这就是http协议无状态做的情况
6)对于浏览器来说,无论谁发来的请求它都不认识,也不会知道你上一次做的事情,下一次请求和上一次请求都是没有关系的,每次请求都是独立的。无论是你发的,别人发的,还是你上次发的请求都是独立的。

7)这样就有一个问题,不记得上一次的操作,也就是不保存你的状态,这就是http是无状态的。这时就要用到cookie来保存我们的状态
8)那么cookie做了什么流程呢?红线是发了post请求,请求过去之后服务器做了一个校验,用户密码登录校验正确之后,返回post请求会在响应数据中多添加了数据并保存在浏览器1中。当浏览器1再次发送请求(橘色的线)时会携带保存的这部分数据。然后服务器再对这部分数据进行校验判断你是登录的用户,然后才让你访问index等需要登录的页面。
9)而浏览器2没有进行登录,也没有服务器在你浏览器上留下的这部分数据,就判断你是未登录用户,然后返回登录页面提示你登录后再访问这个index页面。
10)而这里保存的数据就是cookie。
11)cookie的定义:保存在浏览器本地上一组组键值对
12)cookie的特点:
1. 由服务器让浏览器进行设置的
2. 浏览器保存在浏览器本地
3. 下次访问时自动携带(访问淘宝,携带淘宝给你设置的信息,访问京东,携带京东给你设置的信息)
比如博客园,这里就是基于登录做的


浏览器设置里面找到cookie



关闭cookie:

关闭之后登录的时候那么服务器让浏览器保存cookie,而浏览器设置了不保存,那么我再发送登录进入之后的页面就不再携带这个cookie的信息,就无法登录跳转页面了。博客这里登录会先显示验证通过然后显示红色报错信息。

cookie作用是保存信息的,是浏览器上的一组组键值对,登录验证是它的一个应用,而不是专门做登录用的
cookie还可以这样应用:比如下面这样的页面如果可以设置每页20条数据,那么cookie保存这个数据下次访问还是显示这个数据。保存浏览习惯

cookie投票计数,计数到达次数的浏览器做个限制。应用于简单投票
cookie键值对,GA计数

那么它是如何发送到服务器里面的呢。发送http请求,请求行,请求头,请求体,cookie就保存在请求头当中。多个键值对分号分开。在上面的cookies中将它分开了

两个地方cookie区别;
服务器让浏览器设置,然后浏览器保存在本地,下次访问浏览器的时候自动就携带了这些东西了。

那么服务器端应该在下面设置cookie,也就是登录验证成功重定向操作的时候给你设置一个cookie,

给响应头添加cookie

将csrf的功能注销掉重启服务
这样当我们输入错的时候没有cookie:

当我们form表单填写正确的时候重定向到了首页,在login重定向的时候,显示发送响应cookie让你在浏览器保存了服务端给你设置的键值对

然后重定向访问到index页面,也就是下次访问的时候会自动带上cookie

也就是重定向返回location /index/的时候,就设置了cookie,在HttpResponse响应头中,并将它保存在浏览器中


当浏览器再次访问的时候就会在请求头中携带保存下来的cookie信息

登录页重定向index页面的时候,get index页面的视图函数中要获取到cookie进行判断。请求体发送过来的是字符串,在这里封装成字典。想要用它就用字典的方式获取就行了,[]或点get获取

如果获取的cookie不等于我设置的值那么重定向到登录地址继续登录,否则(cookie验证通过)返回首页内容。

ctrl shift delete清除浏览数据

再去访问index,跳转到登录:


网页能不能访问是根据状态实现的。把登录状态保存在cookie里面,每次请求来的时候先去获取登录状态。没有状态就让它跳转到登录页面,获取到状态就跳转到访问的页面
如下:新添加一个home页面,这个home页面现在不用登录也能访问

index需要校验,home也需要校验,这时候就要用到装饰器了。
1)在需要登录之后才能访问的页面使用装饰器

Cookie的由来
大家都知道HTTP协议是无状态的。
无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。
一句有意思的话来描述就是人生只如初见,对服务器来说,每次的请求都是全新的。
状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。
什么是Cookie
Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。
Cookie的原理
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。
查看Cookie
我们使用Chrome浏览器,打开开发者工具。

Django中操作Cookie
获取Cookie
request.COOKIES['key']
request.get_signed_cookie('key', default=RAISE_ERROR, salt='', max_age=None)
get_signed_cookie方法的参数:
- default: 默认值
- salt: 加密盐
- max_age: 后台控制过期时间

设置Cookie
rep = HttpResponse(...) rep = render(request, ...) rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密盐',...)
参数:
- key, 键
- value='', 值
- max_age=None, 超时时间 #如果不加它,默认退出浏览器cookie就失效,需要重新登录;如果给这个参数设置默认值5,那么5秒后cookie失效
- expires=None, 超时时间(IE requires expires, so set it if hasn't been already.) #ie浏览器使用的超时时间
- path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问 #指定不是根的生效路径,其它的访问都会进入登录页面
- domain=None, Cookie生效的域名 #
- secure=False, https传输 #
- httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
删除Cookie
def logout(request):
rep = redirect("/login/")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的user的cookie值
return rep
访问/logout/,删除了之前在浏览器上设置的值。并将过期时间设置为0

执行删除cookie就是将这两个值一个设置为空,过期时间设置为0


Cookie版登陆校验
cookie版登录

我们也可以通过这个[]来设置:

设置成功,

将一改成100。本质是客户端给服务端一个请求头,请求头里有cookie,cookie里有键值对。服务器回的话会set-cookie的响应头

三种方法是对响应对象做设置:下面两种方法的本质是[]字典类型方法设置键值对

Session
这两个是文件型数据库的表:


执行命令生成session的表,

又上知应用里面有sessions,

sessions应用里的数据存在下面的表中:

将之前设置cookie的改成设置session,在登录post请求中。之前设置的键值对中值为字符串1,而session可以设置数字1。但是后面访问其它页面时

session设置的是数字1,,后面取的进行判断应该是数字1,下面有误

获取的话可以如下获取:




并且session_data会做加密和解密,超时时间也是cookie的超时时间

访问index

超时时间


两周之后cookie会从浏览器清掉,但是session不会从数据库清掉,因为过期了,所以再取取不到了。用下面的方法清除session数据库过期数据

在SQLite数据库中直接修改过期时间会变成时间戳,而mysql中是没有问题的



执行上面的delete方法之后,当前会话对应的cookie还在,但是session表中对应的数据已经被删除了

使用flush

请求发出后响应会将sessionid设置为空,超时时间设置为0。session数据库中的对应记录也被删掉了

并且再次访问sessionid没有了。也就是服务端和客户端都将它删掉了

所以区别:

设置session超时时间:


cookicookie设置10秒

10秒之后cookie不在了但是session表中session还在

过期了的数据要删掉还是要使用:

将过期时间设置为0

过期时间设置为这个了,默认浏览器关闭就失效了

session配置

Session的由来
Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。
问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。
我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。
总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。
Django中Session相关方法
# 获取、设置、删除Session中数据
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1']
# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 会话session的key
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查会话session的key在数据库中是否存在
request.session.exists("session_key")
# 删除当前会话的所有Session数据
request.session.delete()
# 删除当前的会话数据并删除会话的Cookie。
request.session.flush()
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
Session流程解析

Session版登陆验证
def check_login(func): @wraps(func) def inner(request, *args, **kwargs): next_url = request.get_full_path() if request.get_signed_cookie("login", salt="SSS", default=None) == "yes": # 已经登录的用户... return func(request, *args, **kwargs) else: # 没有登录的用户,跳转刚到登录页面 return redirect("/login/?next={}".format(next_url)) return inner def login(request): if request.method == "POST": username = request.POST.get("username") passwd = request.POST.get("password") if username == "xxx" and passwd == "dashabi": next_url = request.GET.get("next") if next_url and next_url != "/logout/": response = redirect(next_url) else: response = redirect("/class_list/") response.set_signed_cookie("login", "yes", salt="SSS") return response return render(request, "login.html")
Django中的Session配置
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用。
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,默认修改之后才保存(默认)


浙公网安备 33010602011771号