day13 cookie与session和中间件

发布于 2022年 01月 24日 09:56

内容概要

  • cookie与session简介
  • django操作cookie与session
  • django中间件简介
  • 如何自定义中间件
  • csrf跨站请求伪造(钓鱼网站)
  • csrf相关操作

cookie与session简介

http协议
	四大特性
    	1.基于请求响应
        2.基于TCP\IP作用于应用层之上
        3.无状态
        	基于http协议通信的服务端无法保存客户端状态
            	纵使见她千百遍 我都当她如初见
        4.无(短)连接
        
随着互联网的发展 很多网站都需要保存客户端状态 为了实现该需求
# cookie与session应运而生(最初的功能核心:保存用户状态)
    cookie:服务端让客户端浏览器保存的数据(kv键值对)
    session:服务端保存的关于用户相关的数据(kv键值对)
    '''session的工作需要依赖于cookie'''
    
# 目前只要是需要用户登录的网站 基本都需要使用cookie
	客户端浏览器也可以拒绝保存cookie

django操作cookie

# 视图函数必须返回HttpResponse对象
    from django.shortcuts import HttpResponse,render,redirect
    return HttpResponse()
    return render()
    return redirect()

# 要想操作cookie必须先产生对象,之后利用对象内置方法操作
    obj1 = HttpResponse()
    return obj1
    obj2 = render()
    return obj2
    obj3 = redirect()
    return obj3

# 设置与获取cookie
    obj.set_cookie()  # 让浏览器保存cookie数据
    request.COOKIES.get()  # 获取浏览器携带过来的cookie数据
    obj.set_cookie(max_age\expires)  # 以秒为基准
    obj.delete_cookie()

# 获取当前用户想要访问的地址
        request.path_info         # 仅获取url的后缀名
        request.get_full_path()   # 获取的全路径,包含问号后面的参数部分

代码练习

from django.shortcuts import render, HttpResponse, redirect


# Create your views here.
from functools import wraps
# 校验登录装饰器
def login_auth(func):
    @wraps(func)  # 装饰器修复技术
    def inner(request, *args, **kwargs):
        # 给参数赋值获取访问之前页面的数据
        target_url = request.path_info
        # 先校验用户的cookie
        cookie_data = request.COOKIES.get('name')
        if cookie_data == 'meng':
            res = func(request, *args, **kwargs)
            return res
        else:
            # 加上target_url可以获取登录之前访问的页面
            return redirect('/login/?target_url=%s' % target_url)
    return inner


@login_auth
def home(request):
    return HttpResponse('登录页面该展示的内容')


@login_auth
def index(request):
    return HttpResponse('index页面,登录页面该展示的内容')


@login_auth
def func(request):
    return HttpResponse('func页面,登录页面该展示的内容')


def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'meng' and password == '123':
            # 先获取用户登录之前需要访问的页面,如果没有数据跳转到首页
            target_url = request.GET.get('target_url', '/home/')  # 如果前面没有数据,使用后面的数据
            obj = redirect(target_url)
            # 设置cookie 
            obj.set_cookie('name', 'meng',expires=3)  # expires:设置几秒丢掉cookie
            # 跳转到首页
            return obj
    return render(request, 'login.html')

# 退出
def logout(request):
    obj = redirect('/home/')
    obj.delete_cookie('name')
    return obj

django操作session

request.session[key] = value  # 设置session
    1.django自动产生一个随机字符串
    2.默认在django_session表中保存随机字符串与数据的对应关系
    3.将随机字符串发送给客户端浏览器保存
    	sessionid:随机字符串

request.session.get(key)  # 获取session
    1.django自动获取浏览器发送过来的cookie数据 获取随机字符串 
    2.拿着随机字符串去django_session表中比对
    3.如果对应上了则获取数据并解密成明文的形式

'''
需要记住的:
	1.django默认的session失效时间>>>:两周(14天)
	2.同一个计算机上一个浏览器只会有一条数据生效,当session过期的时候可能会出现多条
	还有可能是不同浏览器访问,也可能出现多条数据。
'''

# 删除当前会话的所有Session数据
    request.session.delete()  # 只删除浏览器数据,客户端不会删除
  
# 删除当前的会话数据并删除会话的Cookie。
    request.session.flush()   # 推荐使用
    这用于确保前面的会话数据不可以再次被用户的浏览器访问

# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
    * 如果value是个整数,session会在些秒数后失效。
    * 如果value是个datatime或timedelta,session就会在这个时间后失效。
    * 如果value是0,用户关闭浏览器session就会失效。
    * 如果value是None,session会依赖全局session失效策略。
   
# 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流程解析

django中间件

django中间件类似于django的门户 请求来和走都必须经过它
'''
当我们需要给web后端添加一些全局相关的功能时可以使用中间件
	1.校验每个用户的访问频率
	2.校验每个用户的登录状态
	3.用户黑名单、白名单
	4.用户权限
	...
'''
django默认有七个中间件 并且还支持用户自定义中间件
自定义中间件我们可以编写五个方法
	必须掌握的方法
		# process_request(self,request)
        
        	1.当请求来的时候会从上往下依次执行每一个中间件里面的该方法
            如果没有则直接下一个
            2.当该方法返回了HttpResponse对象 那么请求不再继续往后执行
            而是直接原路返回
            
         # process_response(self,request,response)
        	1.当响应返回的时候会从下往上依次执行每一个中间件里面的该方法
            如果没有则直接下一个 该方法默认要返回response
            2.该方法返回什么浏览器就会接收到什么(也就意味着我们可以中途拦截待返回的数据做其他处理)
         # process_request方法如果直接返回HttpResonse对象则直接执行process_response原理返回
        
	需要了解的方法
    	process_view
        	路由匹配成功之后执行视图函数之前自动触发
            
        process_template_response
        	当返回的对象中含有render属性自动触发
            
        process_exception
        	当视图函数报错之后会自动触发

中间件简介

什么是中间件?
    官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

    但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。

    说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

    我们一直都在使用中间件,只是没有注意到而已,打开Django项目的Settings.py文件,看到下图的MIDDLEWARE配置项。
    
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',
]

自定义中间件

中间件可以定义五个方法,分别是:(主要的是process_request和process_response)
必须掌握的方法:
	process_request(self,request)
	process_response(self, request, response)
    
需要了解的方法:
    process_view(self, request, view_func, view_args, view_kwargs)
    process_template_response(self,request,response)
    process_exception(self, request, exception)
    
    以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。

自定义一个中间件实例

process_request

# 我们来看看多个中间件时,Django是如何执行其中的process_request方法的。
# 自定义mymiddleware.py
from django.utils.deprecation import MiddlewareMixin
class MyMdd1(MiddlewareMixin):
    def process_request(self, request):
        print('我是mdd1的request方法')

class MyMdd2(MiddlewareMixin):
    def process_request(self, request):
        print('我是mdd2的request方法')

# views.py
def ab_md(request):
    print('我是视图函数ab_md')
    return HttpResponse('ab_md')
   
# settions.py
MIDDLEWARE = [
    'app01.mymiddleware.MyMdd1',  # 自定义中间件mdd1
    'app01.mymiddleware.MyMdd2'   # 自定义中间件mdd2
]

后端打印:
    我是mdd1的request方法
    我是mdd2的request方法
    我是视图函数ab_md
    
# 总结:
    1.中间件的process_request方法是在执行视图函数之前执行的
    2.当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后的一次执行。
    3.不同中间件之间传递的request都是同一个对象
    4.当该方法返回了HttpResponse对象,那么请求不再继续往后执行,而是直接原路返回

process_response

# 自定义mymiddleware.py
class MyMdd1(MiddlewareMixin):
    def process_request(self, request):
        print('我是mdd1的request方法')

    def process_response(self, request,response):
        print('我是mdd1的response方法')
        return response

class MyMdd2(MiddlewareMixin):
    def process_request(self, request):
        print('我是mdd2的request方法')

    def process_response(self, request,response):
        print('我是mdd2的response方法')
        return response
    
# 其余和上述代码一致
后端打印:
    我是mdd1的request方法
    我是mdd2的request方法
    我是视图函数ab_md
    我是mdd2的response方法
    我是mdd1的response方法
    
# 总结:
    1.当响应返回的时候会从下往上依次执行每一个中间           件里面的该方法,如果没有则直接下一个 该方法默认要返回response
    
    2.该方法返回什么浏览器就会接收到什么(也就意味着我们可以中途拦截待返回的数据做其他处理)  # 原理和击鼓传花一样,一个传一个
    
    3.当中间件返回了HttpResponse对象,那么请求不再继续往后执行,而是直接原路返回
    # process_request方法如果直接返回HttpResonse对象则直接执行process_response原路返回

推荐文章