Cookie

Cookie的由来

Http协议是无状态的

无状态的意思是每次都是独立的请求存在,它的执行情况和结果与前面的请求和后面的请求都无直接关系,它不会受到前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。

一句话来说,人生若只如初见,对服务器来说,每一次的请求都是全新的

状态可以理解为客户端和服务端在某次会话中产生的数据,那无状态的就以为这些数据不会得到保存。会话中的数据又是我们需要保存的,也就是说’保存状态‘。因此诞生cookie

什么是cookie

cookie具体指的是一小段信息,它是服务器发送给存储在浏览器的一组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息

保存在浏览器本地上的一组组键值对

cookie的原理

cookie的工作原理:由服务器产生内容,浏览器收到请求后保存到本地;当浏览器再次访问时,浏览器会自动携带上cookie,这样服务端就可以通过cookie的内容来判断这个是谁了

查看cookie

使用Chrome浏览器,打开开发者工具。

cookie特性

  1. 由服务器让浏览器进行设置的
  2. 访问相应的网站携带对应的cookie

Django操作cookie

1. 设置cookie

# 响应对象设置set_cookie
response.set_cookie('is_login','1')
response.set_cookie(key, value, max_age=5, path='/')
response.set_signed_cookie(key,value,salt='加密盐',...)

参数:

  • key, 键
  • value='', 值
  • max_age=None, 超时时间
  • expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
  • path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
  • domain=None, Cookie生效的域名
  • secure=False, https传输
  • httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

2. 获取cookie

request.COOKIES  {}   value是字符串
request.COOKIES.get('is_login')
request.get_signed_cookie('is_login',salt='xxxx',default='')

get_signed_cookie方法的参数:

  • default: 默认值
  • salt: 加密盐
  • max_age: 后台控制过期时间
  • default=RAISE_ERROR: 默认如果没有cookie则会报错,所以自定义设置以一下比较好

3. 删除cookie

def logout(request):
rep = redirect(reverse('login'))
rep.delete_cookie("user") # 删除用户浏览器上之前设置的user的cookie值
return rep

Cookie登录校验

def login_required(func):
@wraps(func)
def inner(request,*args,**kwargs):
is_login = request.COOKIES.get('is_login')
if is_login != '1':
url = request.path_info
return redirect("{}?returnurl={}".format(reverse('login'),url))
ret = func(request, *args, **kwargs)
return ret
return inner class Login(View):
http_method_names = ['get', 'post'] def get(self, request, *args, **kwargs):
return render(request, 'login.html') def post(self, request, *args, **kwargs):
user_msg = request.POST.get('username')
pass_msg = request.POST.get('password')
user_obj = models.User.objects.filter(username=user_msg, password=pass_msg)
if user_obj:
ret_url = request.GET.get('returnurl')
if ret_url is None:
response = redirect(reverse('publisher'))
else:
response = redirect(ret_url)
response.set_cookie('is_login','1')
return response
return render(request, 'login.html', {'login_error': '用户名或密码错误'}) ## 第二版
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")

Session

Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。

问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。

我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。

总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。

另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。

保存在服务器上的一组组键值对,必须依赖cookie

为什么要有session?

  1. cookie在浏览器本地,不安全
  2. cookie的大小收到限制

Django操作Session的方法

增删改查(session版)

# 设置session
# 当作字典使用即可
request.session[key] =value # 设置session 只能存储可被json序列化的 无法存储对象
request.session.setdefault('k1',123) # 存在则不设置 # 获取session
request.session[key]
request.session.get(key) # 删除
del request.session['k1']
request.session.pop('k1') request.session.delete() # 删除所有的session数据 不删除cookie
request.session.flush() # 删除所有的session数据 删除cookie
# 这用于确保前面的会话数据不可以再次被用户的浏览器访问
# 例如,django.contrib.auth.logout() 函数中就会调用它。 # 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired() # 会话session的key
request.session.session_key # 检查会话session的key在数据库中是否存在
request.session.exists("session_key") # 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。 # 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()

Session流程解析

Session配置

from django.conf import global_settings
from django.contrib.sessions.backends import db 1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)# 存储的位置
# cache cache_db db file singed_cookies
# 支持 数据库 文件 缓存 缓存+数据库(redis) 加密cookie 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=随机字符串(默认)cookie的名字
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数据

django使用redis做session缓存

URL:https://django-redis-chs.readthedocs.io/zh_CN/latest/

Session版登陆验证

from django.shortcuts import render, redirect, reverse, HttpResponse
from app01 import models
from django.views import View
from django.utils.decorators import method_decorator
from functools import wraps def login_required(func):
@wraps(func)
def inner(request,*args,**kwargs):
is_login = request.session.get('is_login')
print(is_login)
if not is_login:
url = request.path_info
return redirect("{}?returnurl={}".format(reverse('login'),url))
ret = func(request, *args, **kwargs)
return ret
return inner class Login(View):
http_method_names = ['get', 'post'] def get(self, request, *args, **kwargs):
request.session.clear_expired()
return render(request, 'login.html') def post(self, request, *args, **kwargs):
user_msg = request.POST.get('username')
pass_msg = request.POST.get('password')
user_obj = models.User.objects.filter(username=user_msg, password=pass_msg)
if user_obj:
ret_url = request.GET.get('returnurl') # 设置session 只能存储可被json序列化的 无法存储对象
request.session['is_login'] = user_msg
# 设置session过期时间
request.session.set_expiry(100) if ret_url is None:
response = redirect(reverse('publisher'))
else:
response = redirect(ret_url)
return response return render(request, 'login.html', {'login_error': '用户名或密码错误'}) @login_required
def singout(request):
rep = redirect(reverse('login'))
request.session.flush()
return rep @method_decorator(login_required,name='dispatch')
class PublisherList(View):
def get(self, request, *args, **kwargs):
all_publishers = models.Publisher.objects.all()
return render(request, 'publisher_list.html', {'all_publishers': all_publishers})

最新文章

  1. 使用Linux碎解二
  2. 快手 KSCAD 5.0 矢量图形设计软件
  3. 用css进行布局
  4. java.lang.ClassNotFoundException: Didn't find class "*****(转载)
  5. Android 设置VPN(pptp连接方式)
  6. 在Android应用中使用OpenGL
  7. 数理方程:Fourier变换与卷积
  8. (译)AngularJS1.3.0 开发者指南(四) -- 控制器
  9. .NET十五周年生日快乐 (3月7日发布Visual Studio 2017正式版?)
  10. 编写原生的Node.js模块
  11. 【mongodb系统学习之四】查看mongodb进程
  12. python函数知识点(详解匿名函数)
  13. Adobe Premiere Pro CS6 下载安装包成功
  14. Python之旅Day6 模块应用
  15. dotnet core 编程规范
  16. oracle SQL 执行顺序
  17. unix缓冲
  18. IIs8 svc
  19. 2018-2019 Russia Open High School Programming Contest (Unrated, Online Mirror, ICPC Rules, Teams Preferred)
  20. 十个书写Node.js REST API的最佳实践(下)

热门文章

  1. hdu 4453 约会安排(线段树区间合并)
  2. 关于分布式唯一ID,snowflake的一些思考及改进(完美解决时钟回拨问题)
  3. Redis设计与实现 -- 链表与字典
  4. topic模式下的收发
  5. spring启动图案修改(纯属好玩)
  6. gradlew compileDebug --stacktrace -info
  7. vmwre虚拟机配置
  8. 手写9x9乘法表,冒泡排序
  9. Factory Methods
  10. TortoiseGit操作之提交代码到远程库