• Django之中间件和Auth模块


    CBV装饰器

    写一个装饰器在session上

    def login_auth(func):
      def inner(request,*args,**kwargs):
        if request.session.get('is_login'):
          return func(request,*args,**kwargs)
           else:
          return redirect('/login/')
        return inner

    三种方法:

    第一种就是直接在里面给方法加上装饰器,方法上面加,不要用原生的装饰器,用的话,只能改参数,那样的话不通用

    第二种就是在类的上面加装饰器,name=‘方法’指向该方法

    from django.utils.decoration import method_decorator
    #
    @method_decorator(login_auth,name='get') # 第二种 name参数必须指定 class MyHome(View):
      # @method_decorator(login_auth) # 第一种 def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post')

    第三种:利用dispatch来装饰所有的方法

        class MyHome(View):
            @method_decorator(login_auth)  # 第三种  get和post都会被装饰
            def dispatch(self, request, *args, **kwargs):
                super().dispatch(request,*args,**kwargs)
            def get(self,request):
                return HttpResponse('get')
    
            def post(self,request):
                return HttpResponse('post')

    中间件

    那么,我们还是先来看一下Django的请求生命周期

    从上面的图中我们可以发现,中间件在这其中起到了很重要的作用。

    它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

    在settings文件里面就有这样的中间件配置


    django默认有七个中间件,但是django暴露给用户可以自定义中间件并且里面可以写五种方法
    ps:

    1.请求来的时候会依次执行每一个中间件里面的process_request方法(如果没有直接通过)
    2.响应走的时候会依次执行每一个中间件里面的process_response方法(如果没有直接通过)

    django中间件能够帮我实现 网站全局的身份验证,黑名单,白名单,访问频率限制,反爬相关
    》》》:django用来帮你全局相关的功能校验

    自定义中间件
    新建一个任意名字的文件夹,里面新建一个任意名字py文件

    from django.utils.deprecation import MiddlewareMixin

    插件类:

    process_request:请求来的时候从上往下依次执行每一个中间件里面的process_request


    process_response :响应走的时候会从下往上依次执行每一个中间件里面的process_response方法


    process_view:路由匹配成功执行视图之前自动触发(从上往下依次执行)


    process_exception:当视图函数报错了,自动触发(从下往上依次执行)


    process_template_response:视图函数返回的对象有一个render()方法

    (或者表明该对象是一个TemplateResponse对象或等价方法)(从下往上依次执行)

    自定义中间件

    from django.utils.deprecation import MiddlewareMixin
    
    
    class MyMiddleWare(MiddlewareMixin):
        def process_request(self, request):
            print('我是第一个自定义的中间件的process_request!')
    # 写一个路由与视图,启动项目,查看打印结果。
    # 再写一个自定义中间件
    
    class MyMiddleWare(MiddlewareMixin):
        def process_request(self, request):
            print('我是第二个自定义的中间件的process_request!')
    # 诠释中间件的执行顺序
    
    
    # 在两个中间件中添加process_response方法。研究中间件消息进出的顺序
    class MyMiddleWare(MiddlewareMixin):
        def process_request(self, request):
            print('我是第一个自定义的中间件的process_request!')
        def process_response(self,request,response):
              print('我是第一个自定义的中间件的process_response')
            return response
    # 再来研究process_request中直接返回HttpReponse对象,会怎么走接下来的process_response
    
    # process_view,process_exception,process_template_response

    csrf(跨站请求伪造)

    先写一个简单的post请求,复现报错信息

    钓鱼网站:银行转账的路径,你是否也可以拿到,然后你做一个跟银行一模一样的页面,也超银行的借口提交数据,当用户在钓鱼网站输入对方账户名和转账金额之后,点击发送。其实内部是将对方账户换成了钓鱼网站的造假人员的账户。造成你转账转错账户的情况

    开两个django项目,模拟转账的现象

    如何区分钓鱼网站和正经网站?在正经网站返回页面的时候,在form表单中偷偷塞一个特殊的字符串,后端记下该页面对应的字符串的值,等用户发post请求来的时候,我先去校验特殊的字符串是否匹配

    如何去写这个特殊的字符串呢?模版语法有一个固定的写法{% csrf_token %},必须写在form表单内

    浏览器查看改标签的值,并且每次都在刷新。再来演示刚刚转账的示例

    ajax中如何设置csrf_token

    # 只想给某个视图韩式加上csrf校验
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    
    # 局部禁用
    @csrf_exempt
    def index(request):
      pass
    
    # 局部使用
    @csrf_protect
    def login(request):
      pass

    转账钓鱼案例

    def transfer(request):
        if request.method == 'POST':
            username = request.POST.get("username")
            money = request.POST.get('money')
            others = request.POST.get('others')
            print('%s 给 %s 转了 %s'%(username,others,money))
        return render(request,'transfer.html')
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
        <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
    </head>
    <body>
    <h1>正经的网站</h1>
    <form action="/index3/" method="post">
    {#    {% csrf_token %}#}
        <p>username:<input type="text" name="username"></p>
        <p>money:<input type="text" name="money"></p>
        <p>others:<input type="text" name="others"></p>
        <input type="submit">
    </form>
    <button>ajax</button>
    <script>
        $('button').click(function () {
            $.ajax({
                url:'',
                type:'post',
                data:{'name':'khan','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
                success:function (data) {
                    console.log(data)
                }
            })
        })
    
    </script>
    
    </body>
    </html>

    另起一个项目,钓鱼页面与原始页面类似

    通过像原网站发送请求,钓鱼网站的一个input框就用户替换了,这时候钱自然就流向了非法分子,有了{% csrf_token %},那么服务端就不在接受钓鱼网站的post请求

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
        <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
    </head>
    <body>
    <h1>钓鱼网站</h1>
    <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>
        <p>others:<input type="text"></p>
        <input type="text" name="others" value="khan" style="display:none">
        <input type="submit">
    </form>
    </body>
    </html>

     

    Auth认证模块

     执行数据库迁移的那两条命令时,即使我们没有建表,也会出现autho_user表,我们一起来看一下怎么操作该表。

    from django.contrib import auth
    from django.contrib.auth.models import User
    def auth_login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            # models.User.objects.filter(username=username,password=password).first()
            user_obj = auth.authenticate(request,username=username,password=password)
            if user_obj:
                # 记录用户状态
                # request.session['name'] = 'khan'
                auth.login(request,user_obj)  # 一旦记录了,可以在任意的地方通过request.user获取到当前登录对象
                return HttpResponse('ok')
    
        return render(request,'auth_login.html')
    
    
    def auth_index(request):
        print(request.user.is_authenticated())  # 判断当前用户是否已经登录
        print(request.user,type(request.user))  # 获取当前登录用户对象
        return HttpResponse('ok')
    
    
    def auth_logout(request):
        auth.logout(request)  # request.session.flush()
        return HttpResponse('ok')
    
    
    def auth_register(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            user_obj = auth.authenticate(request,username=username)
            if user_obj:
                return HttpResponse('当前用户已存在')
            # models.User.objects.create(username=username,password=password)
            # User.objects.create(username=username,password=password)  # 不能再用create创建
            # User.objects.create_user(username=username,password=password)  # 创建普通用户
            User.objects.create_superuser(username=username,password=password,email='123@163.com')  # 创建超级用户
        return render(request,'auth_register.html')
    
    def auth_password(request):
        print(request.user.password)
        is_res = request.user.check_password('khan123')  # 校验密码是否一致
        if is_res:
            request.user.set_password('666')  # 设置新密码
            request.user.save()  # 修改密码必须save保存  不然无效
        return HttpResponse('ok')

    装饰器校验是否登陆及跳转

    from django.contrib.auth.decorators import login_required
    
    @login_required(login_url='/login/',redirect_field_name='old') 
    # 没登陆会跳转到login页面,并且后面会拼接上你上一次想访问的页面路径/login/?next=/test/,可以通过参数修改next键名 def my_view(request): pass

    如果我所有的视图函数都需要装饰并跳转到login页面,那么我需要写好多份。

    其实可以去settings里面去配置

    # 可以在配置文件中指定auth校验登陆不合法统一跳转到某个路径
    LOGIN_URL = '/login/'  # 既可以局部配置,也可以全局配置

    自定义模型表应用auth功能

    第一种:可以建立一对一关系的模型表

    from django.contrib.auth.model import User
    
    class UserDetail(models.Models):
      phone = models.CharField(max_length=11)
      user = models.OnoToOneField(to=User)

    第二种:面向对象继承

    from django.contrib.auth.models import User,AbstractUser
    class UserInfo(AbstractUser):
      phone = models.CharField(max_length=32)
    
    # 需要在配置文件中,指定我不再使用默认的auth_user表而是使用我自己创建的Userinfo表
    AUTH_USER_MODEL = "app名.models里面对应的模型表名"
    承蒙关照
  • 相关阅读:
    省选测试42
    省选测试41
    省选测试40
    省选测试39
    python海龟画图生成星星
    Python-列表简介
    Linux系统中设置默认的Java版本
    虚拟机无线网卡桥接失败
    pycharm设置启动图标
    禁用vscode硬件加速
  • 原文地址:https://www.cnblogs.com/guanlei/p/11048291.html
Copyright © 2020-2023  润新知