目录
一、Cookie与Session的发展史
Cookie和Session是用来在Web应用程序中跟踪用户会话数据的两种常用技术。
【1】Cookie的发展史:
- 1994年,网景通信公司推出了第一个浏览器Cookie技术。Cookie是存储在用户计算机上的小型文本文件,用于跟踪用户在网站上的活动。
- 初始版本的Cookie只能存储很少的数据,并且没有强制加密机制,容易被恶意用户篡改或窃取。因此,随着互联网的快速发展,Cookie引起了一系列安全和隐私问题。
【2】Session的发展史:
- 由于Cookie存在的局限性,Web开发人员开始寻找更安全、可靠的替代方案。1997年,Sun Microsystems提出了基于服务器的会话管理方案,即Session。
- Session是在服务器端存储用户会话数据的一种技术。每当用户访问网站时,服务器会为其创建一个唯一的Session标识符(Session ID),并将会话数据存储在服务器上。
- Session ID一般通过Cookie或URL参数传递给客户端,用于识别用户的会话状态。
【3】Cookie和Session的关系:
- 在实际应用中,Cookie和Session通常结合使用。当用户首次访问网站时,服务器会为其分配一个唯一的Session ID,并将其存储在Cookie中,发送给客户端保存。
- 随后,客户端在每次请求中都会携带该Cookie,服务器通过解析Cookie中的Session ID,读取对应的会话数据,实现用户状态的跟踪和管理。
【4】总结:
- Cookie和Session是Web应用程序中常用的用户会话跟踪技术。
- Cookie通过在客户端存储小型文本文件,并将会话标识符传递给服务器,实现会话状态的保持。
- 而Session则是在服务器端存储会话数据,通过Session ID实现对用户会话的追踪。
- 它们的发展历程与互联网的发展紧密相关,为开发人员提供了更多的选择,以保障安全性和用户体验的提升。
二、Cookie与Session介绍
-
1 网站都没有保存用户功能的需求,所有用户访问返回的结果都是一样的
- 例如新闻、博客、文章...
-
2 出现了一些需要保存用户信息的网站
- 例如京东、淘宝、天猫...
- 3 以登录功能为例:
- 如果不保存用户登录状态,也就意味着用户每次访问网站都需要重复的输入用户名和密码
- 这对用户来说,体验感极差
- 解决办法:
- 当用户第一次登陆成功之后,将用户的用户名和密码返回给用户浏览器,让用户浏览器保存在本地
- 之后访问网站的时候浏览器自动将保存在本地的用户名和密码发送给服务端,服务端获取之后自动验证
- 但是具有极大的安全隐患
- 优化
- 当用户登陆成功之后,服务端产生一个随机字符串(在服务端保存数据,用K:V键值对的形式),交由客户端浏览器保存
- 之后访问服务端的时候,都带着随机字符串,服务端去数据库中比对是否有匹配到的随机字符串,从而获得用户信息
- 但是如果截获到当前随机字符串,那么就可以冒充当前用户,其实还是有极大的安全隐患
- 在web领域没有绝对的安全和绝对的不安全
【1】Cookie
- 服务器保存在客户端浏览器上的信息都可以称之为Cookie
- 它的表现形式一般都是k:v键值对(可以有多个)
【2】Session
- 保存在服务器上的信息都可以称之为Session
- 它的表现形式一般都是k:v键值对(可以有多个)
【3】token
- Session虽然数据是保存在服务端的,但是挡不住数据量大
- 解决办法:服务端不再保存数据
- 登陆成功之后,将一段信息加密处理(用自己独特的加密方式进行加密)
- 将加密之后的结果拼接在信息后面,整体返回给浏览器保存
- 浏览器下次访问的时候带着该信息,服务端自动切取前面的一段信息再次使用自己的加密算法进行加密
- 然后用这段密文与携带过来的密文进行比对
【4】总结
- Cookie就是保存在客户端浏览器上的信息
- Session就是保存在服务端上的信息
- Session是基于Cookie工作的(其实大部分的保存用户状态的操作都需要使用Cookie)
三、Django操作Cookie
- 虽然cookie是服务端告诉客户端浏览器需要保存内容
- 但是客户端浏览器可以选择拒绝保存
- 如果禁止自动保存cookie
- 那么只要是需要登录的网站都没办法正常登录了
-
三板斧--视图函数返回
return HttpResponse()
return render()
return redirect()
- 变形
- 如果想要操作cookie,必须进行以下变形才可以
obj = HttpResponse()
return obj
obj1 = render()
return obj1
obj2 = redirect()
return obj2
【1】设置cookie
obj = HttpResponse()
obj.set_cookie(key,value)
return obj
示例:
def login(request, *args, **kwargs):
if request.method == 'POST':
username = request.POST.get("username")
password = request.POST.get("password")
if username == "dream" and password == "521":
obj = HttpResponse("ok")
obj.set_cookie('sign', 'user')
return obj
else:
return redirect('/login/')
return render(request, 'login.html')
- 取值cookie验证
def home(request, *args, **kwargs):
sign = request.COOKIES.get('sign')
if sign and sign == 'user':
return HttpResponse("这是home页面")
else:
return redirect('/login/')
【2】获取cookie
request.COOKIES.get(key)
【3】设置过期时间
obj = HttpResponse()
obj.set_cookie(key,value,max_age=3)
# 设置超时时间 3s 到期
return obj
- max_age
- 设置超时时间,以秒为单位
- expiress
- 设置超时时间 针对IE浏览器使用,以秒为单位
【4】刪除cookie
obj = HttpResponse()
# 设置超时时间 5s 到期
obj.delete_cookie(key)
return obj
- 注意
- 这里只是拿 HttpResponse 举例,并不是这个参数只能是 HttpResponse
- 比如
- 我们想下一步跳转到某一个功能时,可以是
obj = redirect('/home/') obj.delete_cookie(key) return obj
【5】 登陆功能实现
(1)不设置cookie简单实现
- 路由
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('home/', views.home),
]
- 视图
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == "dream" and password == "521":
# 登陆成功之后,跳转到登陆成功之后才能看到的页面
return redirect('/home/')
return render(request, 'login.html')
def home(request):
return HttpResponse("登陆成功!")
- 前端
<form action="" method="post">
<p>username:<input type="text" name="username" class="form-control"></p>
<p>password:<input type="password" name="password" class="form-control"></p>
<input type="submit" class="btn btn-success">
</form>
- 问题:登陆成功之后的跳转页面,不需要登陆也可以直接访问到,只需要给对应的地址即可
(2) 解决登陆问题
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == "dream" and password == "521":
# 登陆成功之后,保存用户登陆状态
obj = redirect('/home/')
# 让浏览器记录cookie
obj.set_cookie("sign", "1314521")
'''
浏览器不单单只是帮我们保存cookie
而且在后面每次访问的时候都会带着cookie
'''
# 登陆成功之后,跳转到登陆成功之后才能看到的页面
return obj
return render(request, 'login.html')
def home(request):
# 读取携带的cookie,cookie正确登陆成功
if request.COOKIES.get("sign") == "1314521":
return HttpResponse("登陆成功!")
# 读取携带的cookie,cookie不正确跳转到登陆页面
return redirect('/login/')
(3) 迭代-登陆认证装饰器
- 用户如果没有登陆的情况下想访问一个需要登录的页面
- 那么先跳转到登录页面,当用户输入正确的用户名和密码之后
- 再跳转到用户之前想访问的页面去,而不是直接写死
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == "dream" and password == "521":
# 获取用户上一次想要访问的url
# 结果可能为空 -- 直接访问login
tag_url = request.GET.get('tag_url')
if tag_url:
obj = redirect(tag_url)
else:
# 登陆成功之后,保存用户登陆状态
obj = redirect('/home/')
# 让浏览器记录cookie
obj.set_cookie("sign", "1314521")
'''
浏览器不单单只是帮我们保存cookie
而且在后面每次访问的时候都会带着cookie
'''
# 登陆成功之后,跳转到登陆成功之后才能看到的页面
return obj
return render(request, 'login.html')
# 校验用户登录状态的装饰器
def auth_check(func):
def inner(request, *args, **kwargs):
# 获取到用户上一次想要访问的url
tag_url = request.get_full_path()
# 读取携带的cookie,cookie正确登陆成功
if request.COOKIES.get("sign") == "1314521":
res = func(request, *args, **kwargs)
return res
else:
# 读取携带的cookie,cookie不正确跳转到登陆页面
return redirect(f'/login/?next={tag_url}')
return inner
@auth_check
def home(request):
return HttpResponse("home登陆成功!")
@auth_check
def index(request):
return HttpResponse("index登陆成功!")
@auth_check
def func(request):
return HttpResponse("func登陆成功!")
四、Django操作Session
- session数据是保存在服务端的,给客户端返回的是一个随机字符串
- sessionid:随机字符串
【1】设置Session
request.session['key'] = value
【2】获取Session
request.session.get('key')
【3】注意
-
session基于数据库表才能使用的
-
必须先迁移数据库,生成 django_session 表
-
-
session只对当次登录有效
-
主动清除浏览器中本地存在的session
-
验签发现,没有sessionid就会自动生成新的session
-
-
django_sessoin
表中的数据条数取决于浏览器-
同一个计算机(IP地址)上同一个浏览器只会有一条数据生效
-
同一个计算机(IP地址)上多个浏览器会有多个数据生效
-
当session过期的时候,可能会出现多条数据对应一个浏览器
-
但是这些数据不会持久化存储,会被定时清理掉,可以手动清除也可以代码清除
-
-
-
目的是为了节省服务器数据库资源
【4】Session设置过期时间
# 设置session
request.session['key'] = value
# 设置过期时间
request.session.set_expiry()
- 参数
- 整数
- 多少秒过期
- 日期对象
- 到指定日期失效
- 0
- 一旦退出当前浏览器窗口就失效
- 不写
- 失效时间取决于Django内部全局session失效的时间
- 整数
【5】删除session
- 方式一
- 该方法用于删除当前用户的Session数据,但会保留Session的Key。
- 这意味着Session对象本身仍然存在,但其中的数据将被清空。
- 下次访问时,如果Session没有被重新填充,则会得到一个空的Session对象。
request.session.delete()
# 只删除服务端(浏览器)的
- 方式二
- 该方法用于完全删除当前用户的Session,包括Session对象和所有相关数据。
- 下次访问时,将创建一个新的空Session对象。
request.session.flush()
# 把浏览器和数据库里面的session全部清除掉
五、CBV加装饰器的三种方法
(1) 加在CBV视图的get或post方法上
from django.utils.decorators import method_decorator
class HomeView(View):
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
@method_decorator(check_login)
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
(2) 加在dispatch方法上
from django.utils.decorators import method_decorator
class HomeView(View):
@method_decorator(check_login)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
- 因为CBV中首先执行的就是dispatch方法
- 所以这么写相当于给get和post方法都加上了登录校验。
(3) 直接加在视图类上
- 但method_decorator必须传 name 关键字参数
- 如果get方法和post方法都需要登录校验的话就写两个装饰器
from django.utils.decorators import method_decorator
@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")