Django之中间件

Posted mofujin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 装饰器

  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‘ # ‘应用名.类名‘


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

  怎么用

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

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

 

    

以上是关于Django之中间件的主要内容,如果未能解决你的问题,请参考以下文章

Django进阶之中间件

django框架之中间件

django之(中间件)middleware

Django之中间件浅析

Django之中间件

Django之中间件