cookie与session组件
目录
cookie与session组件
一 会话跟踪技术
1 什么是会话跟踪技术
1) 在Web中,客户向某一服务器发出第一个请求开始,会话就开始了,直到客户关闭了浏览器会话结束。
2) 在一个会话的多个请求中共享数据,这就是会话跟踪技术。
3) 例如在一个会话中的请求如下:
-请求银行主页;
-请求登录(请求参数是用户名和密码);
-请求转账(请求参数与转账相关的数据);
-请求信用卡还款(请求参数与还款相关的数据)。
在这上会话中当前用户信息必须在这个会话中共享的,因为登录的是张三,那么在转账和还款时一定是相对张三的转账和还款!这就说明我们必须在一个会话过程中有共享数据的能力。
2 会话路径技术使用Cookie或session完成
-我们知道HTTP协议是无状态协议,即每个请求都是独立的!无法记录前一次请求的状态。但HTTP协议中可以使用Cookie来完成会话跟踪!在Web开发中,使用session来完成会话跟踪,session底层依赖Cookie技术。
3 cookie,session,token
1) cookie: 客户端浏览器上的键值对
2) session: 存在服务端的键值对
3) token: 加密的键值对,如果放在客户端浏览器上,它就叫cookie, 【可以理解为服务端签发的加密字符串】

二 cookie
1 django中cookie的使用
# 0) 会话跟踪,会话保持
# 1) cookie规范
-记住:当前网站在浏览器上cookie个数和大小有限制
-Cookie大小上限为4KB;
-一个服务器最多在客户端浏览器上保存20个Cookie;
-一个浏览器最多保存300个Cookie;
# 2) django中操作cookie
-增:obj.set_cookie('key','value')
-删: obj.delete_cookie('key') # 设置过期
-查: request.COOKIES.get('key')
-改: obj.set_cookie('key','value1')
# 3) 带签名的cookie(加盐,加密)
-增:obj.set_signed_cookie('name','lqz','123')
-删: obj.delete_cookie('name') # 设置过期
-查: request.get_signed_cookie('name',salt='123')
-改: obj.set_signed_cookie('name','lqz','123')
2 cookie版登陆校验
2.1 路由
\urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include('app01.urls', namespace='app01')),
]
app01\urls.py
from django.urls import path
from app01 import views
app_name = 'app01' # 当主路由使用了名称空间的时候,需要设置app_name
urlpatterns = [
path('login/', views.login, name='app01_login'),
path('index/', views.index, name='app01_index'),
path('order/', views.order, name='app01_order'),
path('logout/', views.logout, name='app01_logout'),
path('userinfo/', views.userinfo, name='app01_userinfo'),
]
2.2 视图函数
from django.shortcuts import render, HttpResponse, redirect, reverse
from app01 import models
## 登录认证装饰器
def login_auth(func):
def inner(request, *args, **kwargs):
# 登录校验
name = request.COOKIES.get('name')
if name:
res = func(request, *args, **kwargs)
return res
else:
path = request.get_full_path()
return redirect('/app01/login/?returnUrl=%s' % (path))
return inner
## cookie 版登录
def login(request):
url_index = reverse('app01:app01_index')
if request.method == 'GET':
return render(request, 'login.html')
else:
name = request.POST.get('name')
password = request.POST.get('password')
userinfo = models.Uesr.objects.filter(name=name).values('name', 'password').first()
if userinfo:
if userinfo.get('name') == name and userinfo.get('password') == password:
# 写入cookie, 登录成功,重定向,【有之前页面到登陆前页面,没有则去首页】
path = request.GET.get('returnUrl')
if path:
obj = redirect(path)
else:
obj = redirect(url_index)
obj.set_cookie('name', name)
return obj
else:
return HttpResponse('用户名或密码错误')
else:
return HttpResponse('用户名或密码错误')
# def order(request):
# url_login = reverse('app01:app01_login')
# name = request.COOKIES.get('name')
# if name:
# return render(request, 'order.html')
# else:
# return redirect(url_login)
## 装饰器版本(只要加了装饰器,一旦进入这个视图函数,就表明登录成了)
@login_auth
def order(request):
return render(request, 'order.html')
def logout(request):
obj = HttpResponse('退出登录成功')
obj.delete_cookie('name')
return obj
@login_auth
def userinfo(request):
return render(request, 'userinfo.html')
@login_auth
def index(request):
url_login = reverse('app01:app01_login')
print(url_login)
return render(request, 'index.html')
2.3 模板
login.html
<form action="" method="post">
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="text" name="password"></p>
<p><input type="submit" value="提交"></p>
</form>
order.html
<button><a href="{% url 'app01:app01_logout' %}">退出登录</a></button>
index.html
<h1>index页面</h1>
userinfo.html
<h1>用户信息userinfo</h1>
三 session
1 session由来
Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。
问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。
我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“"账号密码"”等等。
# 总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。
2 django中session的使用
1) 存在于服务端的键值对
2) 同一个浏览器不允许登录多个账户【因为一个浏览器只有一个session_id】,不同浏览器可以登录同一个账户
3) session的使用(必须迁移数据)
-增:request.session['name']=lqz
-查:request.session['name']
-改:request.session['name']=egon
-删:del request.session['name']
-设置过期时间:request.session.set_expiry(10)
4) session的其它使用
-request.session.setdefault('k1',123) # 有的话不改,没有新增
-request.session.get('name',None) # 取值,不会报错
-request.session.keys()
-request.session.values()
-request.session.items()
-request.session.session_key # 获取那个随机字符串,django_session表中session_key字段
-request.session.clear_expired() # 清除过期的session
-request.session.exists("session_key") # 判断这个随机字符串(session_key字段),有没有数据
-request.session.delete() # 删除所有的值,django_session表中删除当前登录者的这条记录
-request.session.flush() # 把cookie和数据库都删除清空
##### session的使用
# django框架默认,把session信息存到数据库中了,django_session表
# 先迁移数据库【比如默认的sqlite数据库,如果事先迁移了表,将django_session表建出来,就不会报错】
def session_set(request):
# request.session是个字典
# 设置session,干了如下几件事
'''
# 一个浏览器,一个随机字符串
1 生成一个随机字符串asdfasdf,把随机字符串和name=lxx数据加密存到django_session表中,
2 会把这个随机字符串放到cookie中
obj.set_cookie('sessionid',asdfasdf)
'''
request.session['name'] = 'lxx'
request.session['age'] = '188'
return HttpResponse('session_set 成功')
# 【每次更新数据,session_data会改变,只要不删除session_id, session_id在有效期内就不会改变】
def session_set2(request):
request.session['name'] = 'alxx'
request.session['xx'] = '777'
return HttpResponse('session_set 成功2')
def session_get(request):
print(request.session.get('name')) # lxx
print(request.session.keys()) # dict_keys(['name', 'xx', 'age'])
print(request.session.values()) # dict_values(['lxx', 'xxxxxxx', '188'])
print(request.session.items()) # dict_items([('name', 'lxx'), ('xx', 'xxxxxxx'), ('age', '188')])
print(request.session.session_key) # j6wgdaaipgxdy3i15wlzwd77trrkybuu
return HttpResponse('得到了 session_key')
3 session原理解析


# 1) 第一次请求:一个浏览器,一个随机字符串
-1 浏览器的首次请求发过来,-->> request.session['name'] = 'lxx'
-2 在请求返回客户端的时候,【在中间件环节】,生成一个随机字符串asdfasdf【即浏览器中的session_id】,把随机字符串【session_id字段的值】和name=lxx数据加密【session_data的值】存到django_session表中
-3 到了浏览器端,会把这个随机字符串放到cookie中-->> obj.set_cookie('sessionid',asdfasdf)
# 2) 后续请求【查数据】的时候:
-1 浏览器请求带着随机字符串【session_id】,去服务端请求数据 request.session.get('name')
-2 浏览器请求在【session中间件】环节,中间件根据随机字符串【session_id】去数据库查,查到数据之后【身份认证成功,免登录】,把数据解密,放到请求request.session.get('name')中,于是乎,我们就拿到了数据。
# 3) 后续请求【写数据】的时候:
-1 浏览器请求发到服务端,request.session['name'] = 'alxx'
-2 请求返回的时候,在【session中间件】环节,由于数据库中有session_id,所以只是把数据部分"**替换和加密**",放到数据库中,session_id不变,以后再请求访问的时候,还是正常的查数据操作。
4 django的session原理流程[全]

5 session版登录认证
5.1 路由
\urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include('app01.urls', namespace='app01')),
path('app02/', include('app02.urls', namespace='app02')),
]
app01\urls.py
from django.urls import path
from app01 import views
app_name = 'app02' # 当主路由使用了名称空间的时候,需要设置app_name
urlpatterns = [
path('login/', views.login, name='app02_login'),
path('index/', views.index, name='app02_index'),
path('order/', views.order, name='app02_order'),
path('logout/', views.logout, name='app02_logout'),
path('userinfo/', views.userinfo, name='app02_userinfo'),
]
5.2 视图函数
from django.shortcuts import render, HttpResponse, redirect, reverse
# Create your views here.
from app01 import models
# 登录认证装饰器
def login_auth(func):
# url_login = reverse('app02:app02_login')
def innder(request, *args, **kwargs):
# 登录校验
name = request.session.get('name')
if name:
res = func(request, *args, **kwargs)
return res
else:
path = request.get_full_path()
# ss = '%s?returnUrl=%s' % (url_login, path)
# return redirect(ss)
return redirect('/app02/login/?returnUrl=%s' % path)
return innder
def login(request):
url_index = reverse('app02:app02_index')
# print(type(url_index), "url_index = reverse('app02:app02_index')")
if request.method == 'GET':
return render(request, 'login.html')
else:
name = request.POST.get('name')
password = request.POST.get('password')
print(name, password)
userinfo = models.User.objects.filter(name=name).values('name', 'password').first()
if userinfo:
if userinfo.get('name') == name and userinfo.get('password') == password:
path = request.GET.get('returnUrl')
if path:
obj = redirect(path)
else:
obj = redirect(url_index)
request.session['name'] = name
return obj
else:
return HttpResponse('y用户名或密码错误')
else:
return HttpResponse('y用户名或密码错误')
@login_auth
def logout(request):
del request.session['name']
return HttpResponse('退出登录成功')
@login_auth
def order(request):
return render(request, 'order.html')
@login_auth
def userinfo(request):
return render(request, 'userinfo.html')
def index(request):
return render(request, 'index.html')
5.3 模板
login.html
<form action="" method="post">
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="text" name="password"></p>
<p><input type="submit" value="提交"></p>
</form>
order.html
<button><a href="{% url 'app01:app01_logout' %}">退出登录</a></button>
index.html
<h1>index页面</h1>
userinfo.html
<h1>用户信息userinfo</h1>
6 django中session的配置
def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False)
# key
# value
# max_age:传个数字,以秒计,过期时间,有默认值 (6天后过期:60*60*24*5)
---了解
# expires:传时间对象,date=datetime.timedelta()
# path:默认 /【访问根路径时显示】 表示当前域下的所有路径 http://127.0.0.1:8000/lxx/dfd/————>> 路径就是/lxx/dfd/
# domain:在哪个*域*下有效
# secure:是否Https传输cookie
# httponly:cookie只支持http传输
# # 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_AGE = 1209600 # Session的cookie失效日期(2周)(默认)***记住
---了解
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
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_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
四 cbv加装饰器
urlpatterns = [
## cbv加装饰器
path('userinfo2/', views.Userinfo.as_view())
]
from django.views import View
from django.utils.decorators import method_decorator
# 使用登录认证装饰器
# 用法一
# @method_decorator(login_auth,name='get')
# @method_decorator(login_auth,name='post')
class UserInfo(View):
# 用法二
@method_decorator(login_auth)
def get(self, request, *args, **kwargs):
return HttpResponse('userinfo get')
@method_decorator(login_auth)
def post(selfself, request, *args, **kwargs):
return render(request, 'userinfo.html')
# 总结:两种用法
-加在类上:@method_decorator(login_auth,name='get')
-加在方法上:@method_decorator(login_auth)

浙公网安备 33010602011771号