• Django-(9)


    内容概览

    • csrf跨站请求伪造
    • csrf预防操作
    • csrf相关装饰器
    • auth认证模块
    • auth_user表切换
    • 基于django中间件设计项目功能

    csrf跨站请求伪造

    1. 简介
      CSRF(Cross-site request forgery)跨站请求伪造,是一种对网站的恶意利用;主要是因为网站的cookie会保存在浏览器中,在有效期中,可以通过一些手段执行用户不想做的功能
    2. 模拟
      创建两个一模一样的网页,一个为真一个为假;在计算机上两个服务端不同端口启动,钓鱼网页提交地址改为真网页的地址
      真:
      <form action="" method="post">
      <p>用户:<input type="text" name="username">p>   转账人
      <p>目标用户:<input type="text" name="target_name">p>		收款人
      <p>转账金额:<input type="text" name="money">p>	转账金额
      <input type="submit">
      form>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      假:
      <form action="http://127.0.0.1:8000/login/" method="post">    直接给真网站发送请求
      <p>用户:<input type="text" name="username">p>
      <p>目标用户:<input type="text">p>	不设置name属性,使这一标签没有实际作用
      <input type="text" name="target_name" value="xxx" style="display: none">	自己设定收款人,并将标签隐藏
      <p>转账金额:<input type="text" name="money">p>
      <input type="submit">
      form>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      如果使用钓鱼网站转账,那么永远只会给xxx转账
    3. 预防
      csrf策略:通过给返回的页面添加一个独一无二的标识信息从而区分正规网站和钓鱼网站的请求

    csrf预防操作

    之前一直注释掉的中间件,就是用来发送标识信息的
    将其注释了代表任意页面都能够直接发送post请求
    启用后再发送post请求需要添加模板语法

    1. form表单
    	<form action="" method="post">
    		{% csrf_token %}    
    	form>
    2. ajax
    	方式1:先编写csrf模板语法,然后利用标签查找和值获取,手动添加
    	{% csrf_token %}
    	<button id="d1">btnbutton>
    	<script>
    	    $('#d1').click(function(){
    	        $.ajax({
    	            url: '',
    	            type: 'post',
    	            data: {"csrfmiddlewaretoken": $('[name="csrfmiddlewaretoken"]').val()},
    	            success: function(){
    	
    	            }
    	        })
    	    })
    	方式2:利用模板语法
    	data: {"csrfmiddlewaretoken": "{{ csrf_token }}"}
    	方式3:通用方式(js脚本)
    	function getCookie(name) {
    	    var cookieValue = null;
    	    if (document.cookie && document.cookie !== '') {
    	        var cookies = document.cookie.split(';');
    	        for (var i = 0; i < cookies.length; i++) {
    	            var cookie = jQuery.trim(cookies[i]);
    	            // Does this cookie string begin with the name we want?
    	            if (cookie.substring(0, name.length + 1) === (name + '=')) {
    	                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
    	                break;
    	            }
    	        }
    	    }
    	    return cookieValue;
    	}
    	var csrftoken = getCookie('csrftoken');
    	function csrfSafeMethod(method) {
    	  // these HTTP methods do not require CSRF protection
    	  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    	}
    	
    	$.ajaxSetup({
    	  beforeSend: function (xhr, settings) {
    	    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
    	      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    	    }
    	  }
    	});
    	将以上代码放入js文件中,需要使用在html中导入文件即可
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    csrf相关装饰器

    当整个网站默认都不校验csrf或者全部校验csrf,可以单独设置指定函数需不需要校验
    FBV:

    from django.views.decorators.csrf import csrf_protect,csrf_exempt
    """
    csrf_protect:校验csrf
    csrf_exempt:不校验csrf
    直接在指定的视图函数上装饰即可
    """
    @csrf_protect
    def func1(request):
    	return HttpResponse('func1')
    @csrf_exempt
    def func2(request):
    	return HttpResponse('func2')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    CBV:

    """CBV针对于装饰器不能够直接添加,需要使用专门添加装饰器的方法"""
    from django import views
    from django.utils.decorators import method_decorator  # 使用该模块添加装饰器
    from django.views.decorators.csrf import csrf_protect, csrf_exempt
    
    @method_decorator(csrf_protect, name='post')  # 方式2:装饰给类,指定装饰的方法名
    class Index(views.View):
        @method_decorator(csrf_protect)  # 方式3:装饰所有方法
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request, *args, **kwargs)
    
        def get(self, request):
            return render(request, 'login.html')
    
        @method_decorator(csrf_protect)  # 方式1:直接在指定方法添加装饰器
        def post(self, request):
            return HttpResponse('post')
    """针对于csrf_exempt只有方式3有效"""
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    auth认证模块

    django执行数据库迁移命令后会产生一张auth_user表
    该表可以配合auth模块做用户相关的功能:登录、注册、修改密码等
    该表还是django admin后台管理默认使用的表
    命令行创建django admin后台管理员:python manage.py createsuperuser

    auth模块常见功能
    1. 创建用户
    from django.contrib.auth.models import User  # 创建用户需要先导入该表
    
    User.objects.create()
    User.objects.create_user(username=username,password=password)
    User.objects.create_superuser(username=username,password=password,email=email)  # 管理员用户需要填写邮箱
    """有三种创建方式
    第一个不建议使用,密码不会自动加密
    第二个为创建普通用户
    第三个为创建管理员用户
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. 校验用户名与密码是否正确
    from django.contrib import auth
    user_obj = auth.authenticate(request,username,password)  # 如果用户名与密码能够匹配上,返回用户对象;否则返回None
    
    • 1
    • 2
    1. 用户登录
    from django.contrib import auth
    auth.login(request,user_obj)  # 提供一个通过校验的用户对象,会在后端为该用户生成相关的session数据
    
    • 1
    • 2
    1. 判断用户是否登录
    res = request.user.is_authenticated
    """当前登录了返回True,否则返回False"""
    
    • 1
    • 2
    1. 获取登录用户对象
    user_obj = request.user
    """
    如果当前登录了返回当前登录用户对象
    如果没有登录则返回一个匿名用户
    """
    print(user_obj.username)  # 如果是匿名用户返回空
    print(user_obj.password)  # 匿名用户点password会报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 校验用户登录装饰器
    from django.contrib.auth.decorators import login_required
    @login_required()
    def func(request):
    	return HttpResponse('func')
    """
    如果当前用户没有登录,跳转到默认登录页面:/accounts/login/
    也可以设置跳转的登录页面:login_required(login_url='/login/')
    如果想要全局都使用一个登录页面,则可以在配置文件中添加配置:LOGIN_URL='/login/'
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 校验密码是否正确
    request.user.check_password('password')
    """会自动加密括号内密码判断是否与当前登录账号密码一致;返回布尔值"""
    
    • 1
    • 2
    1. 修改密码
    request.user.set_password('new_password')
    request.user.save()
    """
    将密码修改为括号内的新密码
    需要注意修改完后必须保存,否则修改不生效
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 注销登录
    from django.contrib import auth
    def logout_fn(request):
    	auth.logout(request)
    	return HttpResponse('logout')
    """调用该函数时,会将当前请求的session信息全部清除"""
    
    • 1
    • 2
    • 3
    • 4
    • 5

    auth_user表切换

    当内置的表字段不够用,想要添加更多字段,那么就可以通过继承内置的AbstractUser类,来定义一个自己的Model类
    models.py:

    from django.contrib.auth.models import AbstractUser
    class Userinfo(AbstractUser):
    	"""继承后直接扩展auth_user表中没有的字段即可"""
    	phone = models.BigIntegerField()
    
    • 1
    • 2
    • 3
    • 4

    在自定义了auth_user表后,需要在setting中配置好,当前应该使用我们自定义的表来做用户认证
    setting:

    AUTH_USER_MODEL = 'app01.Userinfo'  # 应用名加类名
    
    • 1

    基于django中间件设计项目功能

    """python导入模块的第三种方式:通过字符串导入"""
    import importlib
    s1 = 'app01.aaa.func'
    res = importlib.import_module(s1)
    """
    res就相当于是func.py对象,可以直接点出其中方法
    需要注意此方法最多只能到py文件,不能够在细化
    原理相当于是切割字符串,然后导入:s1.rsplit('.',maxsplit=1)
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 配置文件插拔式设计
      需要先创建一个配置文件
    """在里边存放想要执行的类"""
    NOTIFY_FUNC_LIST = [
        'notify.qq.QQ',
        'notify.weixin.WeiXin',
        'notify.msg.Msg',
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    然后在notify包中创建各个类

    class QQ(object):
        def __init__(self):
            pass  # 模拟发送qq之前 应该准备的代码环境
    
        def send(self, content):
            print('qq消息通知:', content)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    创建启动文件

    import notify  # 导入包会导入包的__init__文件
    
    if __name__ == '__main__':
        notify.send_all('messages')
    
    • 1
    • 2
    • 3
    • 4

    在__init__文件中执行各个模块的方法

    import importlib
    import settings
    
    def send_all(content):
        for i in settings.NOTIFY_FUNC_LIST:  # 'day64.notify.qq.QQ',循环获取每个字符串
            module_path, class_str_name = i.rsplit('.', maxsplit=1)  # 'day64.notify.qq'  'QQ',将字符串分为文件路径与类名
            module = importlib.import_module(module_path)  # 获取py文件对象
            class_name = getattr(module, class_str_name)  # 通过文件对象与文件对象中的方法(类名)字符串,使用反射获取真正的类名
            obj = class_name()  # 实例化一个对象
            obj.send(content)  # 由于是鸭子类型,所有类都是同一个方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    【MongoDB】索引 - 复合索引
    Linux中搭建DNS 域名解析服务器(详细版)
    el-tree 虚线连接子节点完美实现
    Golang开发--Goroutine的使用
    2023亚太杯数学建模思路 - 案例:ID3-决策树分类算法
    性能优化:TCP连接优化之四次挥手
    基于生物激励神经网络的室内实时激光SLAM控制方法
    Nanoprobes纳米探针丨Nanogold偶联物的特点和应用
    odoo 开发入门教程系列-准备一些操作(Action)?
    springboot实现redisson分布式锁案例
  • 原文地址:https://blog.csdn.net/AL_QX/article/details/126834964