Django框架-cookie和session以及中间件
一、cookie 和 session
1.为什么会有这些技术
cookie和session的出现是为了保存客户端的用户状态。
究其本质,其实是因为HTTP协议是无状态的,没办法保存客户的登录信息及状态,因此需要用cookie和session来保存用户的状态。
cookie:
cookie是客户端用来记录用户信息的一种容器,它以键值对的形式储存,比方说{'username':'st'}
。
当cookie发送到服务端后,服务端可以根据cookie携带的信息识别用户的身份。可以知道到底是张三在访问服务器还是李四在访问服务器。
这样就导致某些功能在被用户使用时,必须先登录,让服务端知道用户身份后才能使用。比如说淘宝的购物车,每个人都不一样,你只有登陆了,才能访问自己的购物车。
这就导致用户每次访问都要登录,显得很麻烦。如果可以登陆一次就可以记录状态,那就很方便了。
cookie应运而生。
用户登录后,登录信息保存在浏览器cookie中,只需登录一次输入信息,下一次再访问,浏览器就会自动帮你发送cookie。
服务端得知了用户信息,你也不用手动输入多次了,万事大吉,美滋滋!
session:
万事无绝对。
cookie记录的用户信息往往包含了一些隐私信息。比如密码之类的敏感信息。
当cookie保存在浏览器时,cookie中的信息就会遭受各种意外泄露的风险。
一旦泄露,有可能会酿成大祸。
为了解决这个问题,session横空出世。
当用户输入信息登录时,用户信息被传入后端服务器,服务器将这些数据进行加密并保存在服务器中,然后给这份信息贴上一个名为"session_id"的标签。这个"session_id"其实只是一个随机生成的字符串,用来标记这份用户信息,方便查找的。
通过这个"session_id",服务器就可以快速的访问到这份用户信息。
这样有什么用呢?
这样浏览器就不用直接保存用户信息了。服务端可以将"session_id"返回给浏览器,浏览器将"session_id"当做cookie键值对中的值进行保存。
这样,下次用户想要进行访问时,浏览器就将包含"session_id"的cookie发给服务器,服务器通过"session_id"找到之前用户第一次登陆时保存在服务器上的信息,服务器就可以知道用户身份惹!
至此登陆成功!用户再也不用频繁输入信息,也不怕信息泄露惹!
当然,session也并不完美,但是安全性能相比于只有cookie时已经大大提高,从而被广而告之,程序员们纷纷效仿。。。
2. cookie
虽然cookie可以保存在客户端浏览器上,但是由于它是由服务端设置出来的,浏览器有权禁止cookie的写入。
2.1 Django如何设置cookie
需要用views三基类实例化出的obj对象进行cookie设置。
obj = HttpResponse()
# 利用obj对象你才可以操作cookie
# obj = render()
# obj = redirect()
obj.set_cookie('k1','v1')
# 设置用盐加密的cookie
obj.set_signed_cookie(key,value,salt='加密盐',)
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'st' and password == '123':
# 如果登录信息完整,就返回主页
obj = redirect('/home/')
# 告诉浏览器,保存这一对cookie
obj.set_cookie('username','st')
return obj
return render(request,'login.html')
2.2 Django如何获取cookie
def home(request):
if request.COOKIES.get('username'):
print(request.COOKIES.get('username'))
# st
return HttpResponse('只有登录的人才能看到')
return redirect('/login/')
2.3 Django如何设置cookie的超时时间
在set_cookies
使用max_age、expires参数
obj.set_cookie('k1','v1',max_age=3)
obj.set_cookie('k1','v1',expires=3)
# 两个参数都是设置超时时间 并且都是以秒为单位
# 区别:expires可以给IE浏览器设置cookie的超时时间
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'st' and password == '123':
obj = redirect('/home/')
obj.set_cookie('username','st',expires=3)
# 告诉浏览器,保存这一对cookie
# expires=3单位为秒,max_age一样
return obj
return render(request,'login.html')
2.4 Django如何通过cookie跳转到想要访问的页面
可以在登录认证装饰器中完成
# 用来跳回用户登录前想访问的页面的装饰器
from functools import wraps
def login_auth(func):
@wraps(func) # 函数用wraps,类用update_wrapper
def inner(*args,**kwargs):
# 判断当前用户是否登录
request = args[0]
# print(request)
# print(request.GET)
# print(request.path_info) # 只获取url,不获取get参数
# print(request.get_full_path()) # # url+get参数
if request.COOKIES.get('username'):
res = func(*args, **kwargs)
return res
else:
# 获取到用户想要访问的页面的url
path = request.path_info
# 将该url当做get参数传入login函数
return redirect(f'/login/?path={path}')
return inner
# login
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'st' and password == '123':
# 获取get参数,取得用户想要访问的url
path = request.GET.get('path')
if path:
obj = redirect(path)
else:
# 如果path没值,可能用户是直接访问的login视图,因此登录后默认返回到home首页
obj = redirect('/home/')
obj.set_cookie('username','st')
return obj
return render(request,'login.html')
2.5 Django如何删除cookie
用delete_cookie
函数删除cookie。
def logout(request):
obj = redirect('/logout/')
obj.delete_cookie('username')
return obj
3. session
session是保存在服务端上的键值对。
session的工作机制是需要依赖于cookie的。
3.1 Django设置session
默认失效时间为两周,14天
def set_session(request):
request.session['k1'] = 'ok123'
return HttpResponse('session已设置')
Django内部到底发生了什么:
- 将获取到的数据以键值对的形式添加到一个大字典中,将这个字典加密保存。
- 自动生成一个随机的字符串,作为上一步获取的加密数据的session_id。以键值对{'session_id':加密数据}的形式保存在储存器中。可以通过session_id来获取对应的加密数据。
- 将session_id返回给前端浏览器。这样下次浏览器访问时携带cookie,服务器后端可以获取cookie中的session_id,这样就可以通过session_id获取储存器中储存的加密数据。然后通过‘加密数据加密时使用的加密算法’所对应的解密算法将加密数据解密,就可以获取以键值对形式储存的数据了。
- 当下一次同一个浏览器需要在储存一组隐私数据时,django自动解密出该浏览器所对应的大字典,将新加入的键值对添加到这个大字典中,重新加密,保存,替代之前的加密大字典,这样,一个浏览器就会只有一条数据了。
3.2 Django获取session
# 获取session
def get_session(request):
res = request.session.get('k1')
print(res)
return HttpResponse('获取成功')
Django内部到底发生了什么:
- Django服务端从前端浏览器处获取到cookie
- 从cookie中取出相应的'session_id'值
- 在数据库中通过session_id获取对应的大字典加密值
- 将加密大字典解密,获取大字典
- request.session=大字典
- 然后request.session就可以通过'.get'的方式从字典中取值了。
res = dict(request.session)
print(res)
# 强制类型转换一下,发现确实是一个字典
# {'k1': 'ok123', 'k2': 'ok321'}
3.3 Django删除session
# 删除session
def del_session(request):
# 删除当前会话的所有Session数据
# request.session.delete()
# 删除当前的会话数据并删除会话的Cookie,
# 用于确保前面的会话数据不可以再次被用户的浏览器访问.建议使用
request.session.flush()
return HttpResponse('shanle ')
3.4 Django设置session失效时间
# request.session.set_expiry(value)
request.session.set_expiry(5) # 单位为秒
当某条session失效后,这个数据就会从有效的大字典中被筛选出,单独放在session表里作为一条数据,它不会立马被清除,而是先存在session表里,每过一段时间,django就会启用自动清除功能,将失效时间已过的session删除。
3.5 Django设置储存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,默认修改之后才保存(默认)
Django中Session相关设置
二、Django中间件
1. 默认中间件
如果你想要做一些网站的全局性功能,你都应该优先考虑使用django的中间件。
例如:
1.全局的用户登录校验
2.全局的用户访问频率校验
3.全局的用户权限校验()
django的中间件是所有框架里面做的最完善的。
# settings
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
以上就是django默认的七种中间件。
中间件的本质其实就是一个个的类,类中的以下方法会在特定的阶段自动触发:
1.process_request
2.process_response
3.process_view
4.process_template_response
5.process_exception
2. 自定义中间件
自定义中间件需要自己创建一个py文件,名字可以随便取,然后在这个文件中导入MiddlewareMixin
模块产生子类。
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse,render,redirect
# 接下来可以定义类,继承MiddlewareMixin模块,该类就成为了一个中间件
class MyMdd1(MiddlewareMixin):
def process_request(self,request):
pass
# 。。。。。。
2.1. 需要掌握
-
process_request
1.请求来的时候会按照settings配置文件中从上往下的顺序,依次执行每一个中间件内部定义的process_request方法。
2.如果中间件内部没有该方法,直接跳过执行下一个中间件。
3.该方法一旦返回了HttpResponse对象,那么请求会立刻停止往回走,立即原路返回。
4.当process_request方法直接返回HttpResponse对象之后 会直接从当前中间件里面的process_respone往回走。原路返回。没有执行的中间件都不会再执行。
def process_request(self,request):
print('我是第一个中间件里面的process_request方法')
# return HttpResponse("我是中间件一里面的")
-
process_response
1.响应走的时候会按照settings配置文件中从下往上的顺序,依次执行每一个中间件内部定义的process_response方法。
2.该方法必须有两个形参,并且必须返回response形参,不返回直接报错。
3.该方法返回什么(HttpResponsed对象)前端就能获得什么。
def process_response(self,request,response):
"""
:param request:
:param response: 就是后端返回给前端的数据
:return:
"""
print('我是第一个中间件里面的process_response方法')
return response
2.2 了解
-
process_view
1.路由匹配成功之后执行视图函数之前触发。
2.如果该方法返回了HttpResponse对象,那么会从下往上一次经过每一个中间件里面的process_response方法。
def process_view(self,request,view_name,*args,**kwargs):
print(view_name) # 函数内存地址
print(args)
print(kwargs)
print('我是第一个中间件里面的process_view方法')
-
process_template_response
1.在视图函数执行完成后立即执行,但有一个前提条件,那就是视图函数返回的对象必须有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。不然不会触发。
def process_template_response(self, request, response):
print('我是第一个中间件里面的奇葩方法')
return response
# views
def mdzz(request):
print('我是视图函数mdzz')
def render():
return HttpResponse('你好呀 我是奇葩')
obj = HttpResponse('我很好 好的像个傻逼一样')
obj.render = render
return obj
-
process_exception
1.当视图函数中出现错误时会自动触发,顺序是从下往上
def process_exception(self,request,exception):
print('我是第一个中间件里面的process_exception')
print(exception)