• Django之中间件


      一.django中间件()

        1.是什么:django 中间件类似django 门户 保安

        请求的时候需要先经过中间件才能到达django 后端(urls,vies,templates,)

        响应走的时候也是需要经过中间件才能到达web服务网关接口

        django 中间件的默认七个门户

    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.com]mon.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import render,HttpResponse
    
    class Mymidd1(MiddlewareMixin):
        def process_request(selfs, request):
            print('我是第一个中间件里面的process_request方法')
            # 注意:这里是从上到下执行
            return HttpResponse('OK')
        def process_response(self, request, response):
            print('我是第一个中间件里面的process_response响应方法')
            return response
    
    
    class Mymidd2(MiddlewareMixin):
        def process_request(selfs, request):
            print('我是第二个中间件里面的process_request方法')
            # 注意:这里是从上到下执行
    
        def process_response(self, request, response):
            print('我是第二个中间件里面的process_response响应方法')
    
            return response
    
    
    class Mymidd3(MiddlewareMixin):
        def process_request(selfs, request):
            print('我是第三个中间件里面的process_request方法')
            # 注意:这里是从上到下执行
    
        def process_response(self, request, response):
            print('我是第三个中间件里面的process_response响应方法')
            return response
    我是第一个中间件里面的process_request方法
    
    [25/Sep/2019 20:11:54] "GET /test1/ HTTP/1.1" 200 2
    我是第一个中间件里面的process_response响应方法

    如果在请求体中直接有相应结果 就会触发 process_response()  执同级别的process_request( ) 中额结果返回  必须通过process_response() 方法返回 return response 

        

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import render,HttpResponse
    
    class Mymidd1(MiddlewareMixin):
        def process_request(selfs, request):
            print('我是第一个中间件里面的process_request方法')
            # 注意:这里是从上到下执行
    
        def process_response(self, request, response):
            print('我是第一个中间件里面的process_response响应方法')
            return response
    
    
    class Mymidd2(MiddlewareMixin):
        def process_request(selfs, request):
            print('我是第二个中间件里面的process_request方法')
            # 注意:这里是从上到下执行
            return HttpResponse('OK')
        def process_response(self, request, response):
            print('我是第二个中间件里面的process_response响应方法')
    
            return response
    
    
    class Mymidd3(MiddlewareMixin):
        def process_request(selfs, request):
            print('我是第三个中间件里面的process_request方法')
            # 注意:这里是从上到下执行
    
        def process_response(self, request, response):
            print('我是第三个中间件里面的process_response响应方法')
            return response

    我们再次将

    return HttpResponse('OK') 执行procses_request() 函数体中

    我是第一个中间件里面的process_request方法
    我是第二个中间件里面的process_request方法   # 也就是说只要请求中 我们拿到return Httpresponse('') 对象就不会再往下进行请求 通过process_response() 方法进行返回 但会执行同级别的request 请求 


    我是第二个中间件里面的process_response响应方法
    我是第一个中间件里面的process_response响应方法

    总结:浏览器再向服务端发送请求时时通过中间件的执行顺序是从上 往下 一个 个 进行 执行 请求 数据 如果没有 再 往下一层 直到 process_request() 中的一层

    返回了一个 HttpResponse  对象  而 拿到的结果 会往我们redis  存放一份数据  一份返回到浏览器 方便下次在进行同样的数据 请求 redis 可以直接 返回 减少访问数据库的压力

    2.为什么

        (1)中间件的存在就是为了帮我们做检验 一次响应一次请求  如果数据不符合者直接在中间件就给你过滤,不会再走数据库 这样减少数据库的访问 减少数据库的压力  

        (2)网站全局的身份验证,访问频率的限制,权限的校验...要是涉及到全局的校验咱们都要可以在中间件取完成

        (3)django 的中间件是所有web框架中 做得最好的

        3.怎么做

        需要我们掌握的方法有

        1.process_request()方法

        2.process_response()方法

        需要了解的方法

       

    要了解的方法
                            3.process_view()
                                1.在路由匹配成功执行视图函数之前 触发
                                
                            4.process_exception()
                                1.当你的视图函数报错时  就会自动执行
                                
                            5.process_template_response()
                                1.当你返回的HttpResponse对象中必须包含render属性才会触发
                                def index(request):
                                    print('我是index视图函数')
                                    def render():
                                        return HttpResponse('什么鬼玩意')
                                    obj = HttpResponse('index')
                                    obj.render = render
                                    return obj

    总结:

        

      二.基于中间件的解决跨站请求伪造

        1.钓鱼网站伪造

    后端代码

    def transfer(request):
        # 其他网站会向我们中国银行的网站访问一个页面 然后给用户输入 name='' 和 vlue= ;写的是我们自己的账号
        # 我们一旦提交 相当于向钓鱼网站进行转账 仿真页面
        # 真实网站
        if request.method == 'POST':
            username = request.POST.get('username')
            money = request.POST.get('money')
            to_name = request.POST.get('to_name')
            print(' %s向%s 转账%s '%(username,to_name,money))
    
        return render(request,'transfer.html')

    前端代码

    </head>
    <body>
    {#{% csrf_token %}#}
        <h1>中国银行</h1>
        <form action="" method="post">
            <p>username:<input type="text" name="username"></p>
            <p>money:<input type="text" name="money"></p>
    #1 伪造的网站向中国银行请求一个一摸一样的页面
    # 2伪造得的网站在input 框内做手脚 将用户提交的name='to_name'
    属性去除 相当于 后端没办法识别
    
    # 4 然后我们自己设置一个input 框 有name='to_name' 属性 将value=‘ccoo’ 目标账户设置为默认
            <p>to_name:<input type="text" name='to_name'></p>
            <input type="submit">
        </form>
    
    </body>
    </html>

    伪造网站

    def transfer(request):
        # 其他网站会向我们中国银行的网站访问一个页面 然后给用户输入 name='' 和 vlaue= ;写的是我们自己的账号
        # 我们一旦提交 相当于向钓鱼网站进行转账 仿真页面
        # 真实网站
        # 只需跳转页面即可
        return render(request,'transfer.html')

    前端代码

    {#{% csrf_token %}#}
        <h1>钓鱼网站</h1>
            这里就是向中国银行请求一个页面 然后开始设置input 框
        <form action=" http://127.0.0.1:8000/transfer/" method="post">
            <p>username:<input type="text" name="username"></p>
            <p>money:<input type="text" name="money"></p>
    {#        不设置name属性#}
            <p>to_name:<input type="text"></p>
            <input type="text" name="to_name" value="hhh" style="display: none">
            <input type="submit">
        </form>
    
    </body>
    </html>

        2.如何解决:Django 跨站请求伪造

        直接在form表单 {% csrf_token%} 

       <form action="" method="post">
              {% csrf_token %}
            <p>username:<input type="text" name="username"></p>
            <p>money:<input type="text" name="money"></p>
            <p>to_name:<input type="text" name='to_name'></p>
            <input type="submit">
        </form>

          form 表单 {%csrf_token%}

          ajax 的三种处理csrf 的方法

          第一种ajax 提交form 表单 数据

       data:{'username':'koko','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},   注意 value 的来源 是form  的%csrf_token%{}表单
    <body>
    {#{% csrf_token %}#}
        <h1>中国银行</h1>
    
        <form action="" method="post">
              {% csrf_token %}
            <p>username:<input type="text" name="username"></p>
            <p>money:<input type="text" name="money"></p>
            <p>to_name:<input type="text" name='to_name'></p>
    {#        <input type="submit" class="c1">#}
        </form>
    <button class="c1">ajax提交</button>
    </body>
    
    
    
    <script>
        $('.c1').on('click',function () {
            $.ajax({
                url:'', // 路径这里有三种 类似:action 可以写全路径 默认不写诗当前地址
                type:'post',  //methon
                data:{'username':'koko','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},
                success:function (data) {
                    alert(data)
    
                }
            })
    
        })
    
    
    </script>
    </html>

    第二种

      data:{'username':'koko','csrfmiddlewaretoken':'{{ csrf_token }}'},   
    </head>
    <body> {#{% csrf_token %}#} <h1>中国银行</h1> <form action="" method="post"> {% csrf_token %} <p>username:<input type="text" name="username"></p> <p>money:<input type="text" name="money"></p> <p>to_name:<input type="text" name='to_name'></p> {# <input type="submit" class="c1">#} </form> <button class="c1">ajax提交</button> </body> <script> $('.c1').on('click',function () { $.ajax({ url:'', // 路径这里有三种 类似:action 可以写全路径 默认不写诗当前地址 type:'post', //methon {#data:{'username':'koko','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#} data:{'username':'koko','csrfmiddlewaretoken':'{{ csrf_token }}'}, success:function (data) { alert(data) } }) }) </script> </html>

    第三种

     在script 的上方直接引入

    {% load static  %}
    <script src="{% static 'ajax_js.js' %}"></script>
     // 第三种方式 :直接引入js文件
    </head>
    <body>
    {#{% csrf_token %}#}
        <h1>中国银行</h1>
    
        <form action="" method="post">
              {% csrf_token %}
            <p>username:<input type="text" name="username"></p>
            <p>money:<input type="text" name="money"></p>
            <p>to_name:<input type="text" name='to_name'></p>
    {#        <input type="submit" class="c1">#}
        </form>
    <button class="c1">ajax提交</button>
    </body>
    
    
    {% load static  %}
    <script src="{% static 'ajax_js.js' %}"></script>
    <script>
    
        $('.c1').on('click',function () {
            $.ajax({
                url:'', // 路径这里有三种 类似:action 可以写全路径 默认不写诗当前地址
                type:'post',  //methon
                {#data:{'username':'koko','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#}
                {#data:{'username':'koko','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
                // 第三种方式 :直接引入js文件
                data:{'username':'koko'},
                success:function (data) {
                    alert(data)
    
                }
            })
    
        })
    
    
    </script>
    </html>

      三.跨站请求伪造象关装饰器

    如果是csrf_protect 那么有三种方式


    1.当你网站全局都需要校验csrf的时候 有几个不需要校验该如何处理
    2.当你网站全局不校验csrf的时候 有几个需要校验又该如何处理

    from django.views import View
    from django.utils.decorators import method_decorator
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    # 如果是接受跨站请求的保护 则用csrf_protect
    # 这是保护的第三种方法
    # @method_decorator(csrf_protect,name='post')   # 指名道姓
    class MyView(View):
        # 这是第二种保护
        # 任务的分发
        # @method_decorator(csrf_protect)
        def dispatch(self, request, *args, **kwargs):
            res = super().dispatch(request,*args,**kwargs)
            return res
    
        def get(self,request):
    
            return HttpResponse('get')
        # AttributeError at /my_views/
        # 'MyView' object has no attribute 'COOKIES'
        # @csrf_protect 也就是说我将后端的中间件注释 掉他就不会 阻拦我 发送post 数据凡是我放这个保护的装饰器 就会将这个post
        # 阻拦数据传数
        # 这是第一种
        # @method_decorator(csrf_protect)
        def post(self,request):
    
            return HttpResponse('post')

    如果是csrf_exempt 只有两种(只能给dispatch装)   特例

    # @method_decorator(csrf_protect,name='post')   # 指名道姓
    class MyView(View):
        # 这是第二种保护
        # 任务的分发
    
        # 不保护数据的安全习性
        # @method_decorator(csrf_exempt,name='dispatch')
        def dispatch(self, request, *args, **kwargs):
            res = super().dispatch(request,*args,**kwargs)
            return res
        
        def get(self,request):
    
            return HttpResponse('get')
        # AttributeError at /my_views/
        # 'MyView' object has no attribute 'COOKIES'
        # @csrf_protect 也就是说我将后端的中间件注释 掉他就不会 阻拦我 发送post 数据凡是我放这个保护的装饰器 就会将这个post
        # 阻拦数据传数
        # 这是第一种
        # @method_decorator(csrf_protect)
        # @method_decorator(csrf_exempt,name='post')
        # 放这里是不行的 起不到效果
        def post(self,request):
    
            return HttpResponse('post')

      四.auth模块

      注意事项:如果用了auto模块就必须用全套

      1.创建超级用户和普通用户

    普通用户和超级用户的区别是 超级用户可以进行django 后台admin 的管理 

      2.创建普通用户

      普通用户

      增

    from django.contrib.auth.models import User
    
    
    def register(request):
    
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
    
            user_obj = User.objects.filter(username=username)
            if not user_obj:
            # 创建普通用户和超级用户
            # 注意:别再用create 的方法这里的是auth模块
                User.objects.create_user(username=username, password=password)  #  创建普通用户
                # User.objects.create_superuser(username=username, password=password)  # 这是创建超级用户
                return HttpResponse('注册成功')
        return render(request,'login.html')

      删

      用户注销

      

    @login_required  # 无参装饰器
    def logout(request):
        # request.session.flush()  # 没问题
        auth.logout(request)  # ok
        return HttpResponse('注销成功')

      改

    # 装饰器
    from django.contrib.auth.decorators import  login_required
    
    # 修改密码
    @login_required  #  # 自动校验当前用户是否登录  如果没有登录 默认跳转到 一个莫名其妙的登陆页面
    def set_password(request):
        if request.method == 'POST':
            old_pwd = request.POST.get('old_pwd')
            print(old_pwd)
            new_pwd = request.POST.get('new_pwd')
            # 如何检验当前输入的密码和数据库的密码一致
            is_valid = request.user.check_password(old_pwd)
            # 会将当前输入的密码进行自动加密 然后去数据库中比对当前的用户的密码
            if is_valid:
                request.user.set_password(new_pwd)
                # 修改密码后一定记得save() 保存
                request.user.save()
                return HttpResponse('修改成功')
    
            else:
                return HttpResponse('密码有误')

      查 

        is_valid = request.user.check_password(old_pwd)
            # 会将当前输入的密码进行自动加密 然后去数据库中比对当前的用户的密码

      1.用户登录

    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            user_obj = auth.authenticate(username=username,password=password)  # 必须用户auth 模块 因为数据库的密码是秘文
            if user_obj:
                # 保存sessioon 值
                auth.login(request,user_obj)  # 将用户的状态保存在session中
                #  """只要执行了这一句话  你就可以在后端任意位置通过request.user获取到当前用户对象"""
                return HttpResponse('登录成功')
            else:
                return HttpResponse('用户不存在')
        # 先返回一个页面
        return render(request,'register.html')

      

    2.# 判断用户是否登录
    def check_auth(request):
        print(request.user)  # koko
        print(request.user.is_authenticated)  # 判断用户是否登录CallableBool(True)
        return HttpResponse('ok')

      检验用户是否登陆 auth 装饰器

     1装饰器的局部设置 

    @login_required(login_url='/login/')  # 如果没有登录 我们需要指定一个登陆的网址让他进行跳转 局部设置
    那这样不是很麻分每个函数都的加
    2.装饰器的全局设置
    别急 我们有更好的方法 就是在settings 中 设置全局的LOGIN_URL = 'login
    # auth登陆认证装饰器 跳转的url
    LOGIN_URL = 'login'
    
    
    # 告诉django  orm不再使用auth默认的表  而是使用你自定义的表
    AUTH_USER_MODEL = 'app01.Userinfo'  # '应用名.类名'

      3.自定义userinfo 将不会在django 表中创建auth_user  可以增强拓展性 添加新字段

      如何做

    自定义auth_user表
    from django.contrib.auth.models import AbstractUser
    # Create your models here.
    # 第一种 使用一对一关系 不考虑

    # 第二种方式 使用类的继承
    class Userinfo(AbstractUser):
    # 千万不要跟原来表中的字段重复 只能创新
    phone = models.BigIntegerField()
    avatar = models.CharField(max_length=32)

    # 一定要在配置文件中 告诉django
    # 告诉django orm不再使用auth默认的表 而是使用你自定义的表
    AUTH_USER_MODEL = 'app01.Userinfo' # '应用名.类名'    # 注意了哈项目中的mdels  创建Userinfo(Abs) 继承我们数据库的表 必须在settings 中告诉django ORM 不在使用默认的表 而是使用咱们自定义的表


    1.执行数据库迁移命令
    所有的auth模块功能 全部都基于你创建的表
    而不再使用auth_user

      怎么用

    五.settings中的中间件原理 原型的思路 如何实现同时发送给不同功能函数 实现统一的接口的功能 类似鸭子类型 

    设计思想(****************) 插拔式

    六.序列化组件DRF 框架

        

  • 相关阅读:
    Linux.NET学习手记(1)
    初识Entity Framework CodeFirst(3)
    初识Entity Framework CodeFirst(2)
    Linux.NET学习手记(3)
    Linux.NET学习手记(2)
    第四次博客作业结对项目
    [转]制作BlogWriter 博客客户端
    【整理】C# WinFrom 中如何txt内容与dataGridView互动
    将字符串给datetimepicker赋值
    (转)koograExcel文件读取利器的使用
  • 原文地址:https://www.cnblogs.com/mofujin/p/11587092.html
Copyright © 2020-2023  润新知