• django框架之中间件 Auth模块


    CBV加装饰器

    方式一:装饰器加到想装饰的方法上

    方式二:装饰器加到class前面,通过name参数指定被装饰的方法

    方式三:重写dispatch(django分发CBV视图函数),直接给dispatch装饰,该类中所有对象方法都将被装饰 

    from django.shortcuts import render, HttpResponse, redirect
    from django.views import View
    from functools import wraps
    from django.utils.decorators import method_decorator
    
    
    def login(request):
        if request.method == 'POST':
            name = request.POST.get('name')
            pwd = request.POST.get('pwd')
            if name == 'Tom' and pwd == '123':
                request.session['name'] = 'Tom'
                return redirect('/home/')
        return render(request, 'login.html')
    
    
    def login_auth(func):
        @wraps(func)
        def inner(request, *args, **kwargs):
            if request.session.get('name'):
                return func(request, *args, **kwargs)
            return redirect('/login/')
        return inner
    
    
    # @method_decorator(login_auth, name='get')  # 第二种,name参数必须指定
    class MyHome(View):
    
        @method_decorator(login_auth)  # 第三种,拦截django分发视图函数的过程
        def dispatch(self, request, *args, **kwargs):
            super().dispatch(request, *args, **kwargs)
    # @method_decorator(login_auth) # 第一种 def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')

    中间件

    处理Django的请求和响应的框架级别的钩子,相当于django的门户;
    用于在全局范围内改变Django的输入和输出的插件系统,
    本质上就是一个自定义类,Django框架会在请求的特定的时间去执行这些方法。

    django中间件可以实现网站全局相关的功能校验:身份验证(RBAC基于角色的权限管理),黑白名单、访问频率限制、反爬相关....
    中间件在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',
    ]

    django默认7个中间件,给用户提供五个自定义中间件的方法:

    process_request(self,request)  

    process_view(self, request, view_func, view_args, view_kwargs)

    process_template_response(self,request,response)

    process_exception(self, request, exception)

    process_response(self, request, response)  

     

    1)process_request 请求时触发,从上往下依次执行,没有该方法则直接通过 ******

    返回值None:继续往后执行;

    返回HttpResponse对象:将从同级别process_response返回该对象给浏览器

    2)process_view 路由匹配成功,执行视图函数之前触发,从上往下依次执行

    返回值None:继续往后执行;

    返回HttpResponse对象:将从下往上依次执行每个process_response,返回该对象给浏览器

    3)process_exception 视图函数报错时自动触发,从下往上依次执行

    4)process_template_response 视图函数返回的对象有一个render()方法时触发(或表明该对象是TemplateResponse对象或等价方法)

      从下往上依次执行,中间报错无返回函数,不会执行

    5)process_response 响应时触发,从下往上依次执行 ******

    必须将response形参接收的数据返回,不然直接报错

    自定义中间件

    1. 新建一个文件夹,放入自定义中间件.py文件

    2. 导模块导入MiddlewareMixin

    3. 自定义继承MiddlewareMixin的类(中间件)

    4. 将自定义中间件路径在settings.py文件中的 MIDDLEWARE列表 注册

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    
    class MyMiddleWare(MiddlewareMixin):
        def process_request(self, request):
            print('process_request 自定义No.1 方法')
            # return HttpResponse('haha')
    
        def process_response(self, request, response):
            print('process_response 自定义No.1 方法')
            return response
    
        def process_view(self, request, view_func, view_args, view_kwargs):
            print('process_view 自定义No.1 方法')
            print(view_func.__name__, view_func)
            return HttpResponse('**************')
    
        def process_exception(self, request, exception):
            print('process_exception 自定义No.1 方法')
            print(exception)
    
        def process_template_response(self, request, response):
            print('process_template_response 自定义No.1 方法')
            return response
    
    
    class MyMiddleWare1(MiddlewareMixin):
        def process_request(self, request):
            print('process_request 自定义 No.2 方法')
            # return HttpResponse('xixi')
    
        def process_response(self, request, response):
            print('process_response 自定义No.2 方法')
            return response
    
        def process_view(self, request, view_func, view_args, view_kwargs):
            print('process_view 自定义No.2 方法')
            print(view_func.__name__, view_func)
    
        def process_exception(self, request, exception):
            print('process_exception 自定义No.2 方法')
            print(exception)
    
        def process_template_response(self, request, response):
            print('process_template_response 自定义No.2 方法')
            return response
    from django.shortcuts import HttpResponse
    
    
    def index0(request):
        print('我是视图函数index')
        # jhgyuy
        return HttpResponse('index')
    
    
    def index(request):
        print('我是视图函数index')
    
        def render():
            print("in index/render")
            return HttpResponse("564K")
        rep = HttpResponse("OK")
        rep.render = render
        # jkgjlie
        return rep
        'app01.mymiddle.ware.MyMiddleWare',
        'app01.mymiddle.ware.MyMiddleWare1',

    Csrf 跨站请求伪造

    模拟钓鱼网站过程

    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')
    <h1>正常网站</h1>
    <form action="" method="post">
        <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>
    <h1>钓鱼网站</h1>
    <form action="" 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="Tom" style="display:none">
        <input type="text">
    </form>

    钓鱼网站和正常网站页面完全一样(路径有别),在钓鱼网站中,第三个others参数另一方账户无法正常输入,

    但提交的数据最终提交到正常网站,操作成功,但转账将将转到别的账户,这样,网站存在很大的风险.......

     

    django框架通过中间件 'django.middleware.csrf.CsrfViewMiddleware',可以动态生成一条随机数据,每刷新一次页面重新生成,将该数据附在提交数据中,若该数据不存在,或者和该网站内部的数据无法匹配上,即拒绝执行后续操作。如何在post请求中携带该数据?可将该该数据隐藏于一个标签:

    1. form表单跨站请求伪造:

    {% csrf_token %}

    2. Ajax跨站请求伪造,data中加入该键值对:

    'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()

    or

    'csrfmiddlewaretoken':'{{ csrf_token }}'

     

    页面数据:<input type="hidden" name="csrfmiddlewaretoken" value="CWg1rnImJfBiJrdVV6iGORUQQHrIAkWJn3nU3VdFnJmNXx8FTac1UZk2eIsQa6Cz"

    <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>others:<input type="text" name="others"></p>
        <input type="submit">
    </form>
    {% csrf_token %}
    
    <button>ajax</button>
    
    <script>
        $('button').click(function () {
            $.ajax({
                url:'',
                type:'post',
                data:{'name': 'jason','csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()},
    
                succecc:function (data) {
                    console.log(data)
                }
            })
        })
    </script>

    单独配置csrf校验

    全局校验csrf时,某个视图函数不需要校验;全局不校验时,某个视图函数需要校验?

    1.FBV的csrf校验

    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    
    
    @csrf_exempt  # 不校验csrf
    def exempt(request):
        return HttpResponse('exempt')
    
    
    @csrf_protect  # 校验csrf
    def protect(request):
        return HttpResponse('protect')

    2. CBV的csrf校验

    csrf_protect 校验:和正常的CBV装饰器一样,三种

    # @method_decorator(csrf_protect, name='post')  # 第一种
    class index2(View):
        @method_decorator(csrf_protect)
        def dispatch(self, request, *args, **kwargs):  # 第三种
            super().dispatch(request, *args, **kwargs)
    
        def get(self, request):
            return HttpResponse('get')
    
        # @method_decorator(csrf_protect)  # 第二种
        def post(self, request):
            return HttpResponse('post')

    csrf_exempt校验:不能单独给一个方法加校验,只能配置到一个路由下,两种

    @method_decorator(csrf_exempt, name='dispatch')  # 第一种
    class index1(View):
        # @method_decorator(csrf_exempt)  # 第二种
        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')

     

    Auth模块

    django自带的用户功能模块

    常用语句:

    auth.authenticate(request, **kwargs)    查询用户

       .login(request, user_obj)        记录用户登录状态,任何地方request.user获取登录对象

       .logout(request)            退出登录

     

    User.objects.create(**kwargs)         新建用户,密码是明文

     .create_user(**kwargs)     新建用户,普通用户

     .create_superuser(**kwargs)  新建vip,必须有Email,具有Django后台管理登录权限

    命令:python3 manage.py createsuperuser     创建超级用户:vip

     

    request.user                 获取当前登录对象

     .is_authenticated()          是否登录

     .password             查询密码

     .check_password('num')      核对密码是否正确

     .set_password('num')        修改密码

     .save()              保存修改    

     

    登录

    from django.contrib import auth
    
    
    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'] = 'jason'
                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('index')
    
    
    def auth_logout(request):
        auth.logout(request)  # request.session.flush() 退出登录
        return HttpResponse('ok')

    注册

    from django.contrib.auth.models import User
    
    
    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('当前用户已存在!')
            # User.objects.create(username=username, password=password)  # 密码是明文
            # User.objects.create_user(username=username, password=password)  # 普通用户
            User.objects.create_superuser(username=username, password=password, email='123@qq.com')  # vip,必须有Email
        return render(request, 'auth_register.html')

    修改密码

    def auth_password(request):
        print(request.user.password)  # 拿到密码(密文)
        is_true = request.user.check_password('123')  # 核对密码
        if is_true:
            request.user.set_password('321')  # 修改密码
            request.user.save()  # 保存修改
    
        return HttpResponse('change ok')

    登录验证

    auth模块提供登录验证功能,需导入login_required

    from django.contrib.auth.decorators import login_required
    
    
    # 局部登录验证
    @login_required(login_url='/auth_login/')  # 默认跳转登录'/login/',路径不同则需指定
    def auth_home(request):
        return HttpResponse('必须登录才能访问')

    所有视图函数都需要登录验证,可以在settings.py设置全局登录参数配置

    # auth 没有登录,则自动跳转登录页面
    LOGIN_URL = '/auth_login/'

    Auth模块自定义表

    1. 导入模块中的数据:User, AbstractUser

    2. 在settings.py中配置好参数,使用自定义的表名

    AUTH_USER_MODEL = 'app名.models对应的模型表名'

    3. 在使用Auth模块的的常用语句时,使用自定义类名即可

    models.py

    from django.db import models
    from django.contrib.auth.models import User, AbstractUser
    
    
    class UserInfo(models.Model):  # 第一种:一对一关联表(了解)
        phone = models.CharField(max_length=32)
        avatar = models.CharField(max_length=32)
        ab = models.OneToOneField(to=User)
    
    
    class Userinfo(AbstractUser):   # 第二种:面向对象的继承AbstractUser
        phone = models.CharField(max_length=32)
        avatar = models.CharField(max_length=32)

    settings.py

    # 告诉django不在使用默认的auth_user,使用自定义的表
    AUTH_USER_MODEL = 'app01.Userinfo'
  • 相关阅读:
    Project Euler 97 :Large non-Mersenne prime 非梅森大素数
    Project Euler 96:Su Doku 数独
    Project Euler 95:Amicable chains 亲和数链
    Project Euler 94:Almost equilateral triangles 几乎等边的三角形
    Project Euler 93:Arithmetic expressions 算术表达式
    Project Euler 92:Square digit chains 平方数字链
    Project Euler 91:Right triangles with integer coordinates 格点直角三角形
    Project Euler 90:Cube digit pairs 立方体数字对
    Project Euler 89:Roman numerals 罗马数字
    Project Euler 88:Product-sum numbers 积和数
  • 原文地址:https://www.cnblogs.com/zhouyongv5/p/11047224.html
Copyright © 2020-2023  润新知