• Day 64 django csrf操作 auth认证模块 项目功能封装优化


    Day 64 django csrf操作 auth认证模块 项目功能封装优化

    1、csrf跨站请求伪造

    简介
    钓鱼网站:假设是一个银行一摸一样的网址页面 用户 用户在该页面上转账
    账户的钱会减少 但是受益人却不是自己想要转账的那个人

    模拟
    一台计算机上两个服务端不同端口启动 钓鱼网站地址改为正规网站的地址

    钓鱼网站
    style="display: none"

    div class="container">
            <div class="row">
                <form action="https://127.0.0.1/8000/transfer/" method="post">
                    <p>用户名:<input type="text" name="user"></p>
                    <p>转入用户:<input type="text"></p>
                    <p><input type="text" name="target" value="kk" style="display: none"></p>
                    <p>转账金额<input type="text" name="price"></p>
                    <p><input type="submit" name="转账"></p>
                </form>
    
            </div>
        </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    预防
    csrf策略:通过在返回的页面上添加独一无二的标识信息从而区分正规网站和钓鱼网站的请求

    2、csrf操作

    2.1、form表单

    <form action="" method=:"post">
        {% csrf_token %}
    </form>
    
    • 1
    • 2
    • 3

    2.2、ajax

    方式一: 先编写csrf模板语法 然后利用标签查找和值获取 手动添加

    {% csrf_token %}
    #  利用属性选择器查找
    data:  {'username':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]')}
    
    • 1
    • 2
    • 3

    方式二: 直接利用模板语法即可

    data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
    
    • 1

    方式三: 通用方式(js脚本)
    扩展性更高高

    # 在配置文件中中 配置固定地址
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR,'static')
    ]
    
    #直接在html中引入
    <script src="/static/csrf.js"></script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    创建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);
        }
      }
    });
    
    • 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

    3、csrf相关装饰器

    当整个网站默认都不校验csrf 但是局部视图函数需要校验

    当整个网站默认都校验csrf 但是局部视图函数不许哟啊校验

    3.1、FBV

    需要先导入 模块 导入装饰器

    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    
    • 1

    校验csrf
    csrf_protect

    不校验csrf
    csrf_exempt

    @csrf_protect
    def home(request):
        return HttpResponse('hahaha')
    
    • 1
    • 2
    • 3

    3.2、CBV

    针对CBV不能直接在方法上添加装饰器 需要借助于专门添加装饰器的方法

    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django import views
    from django.utils.decorators import method_decorator
    
    #方式二:直接在类上面添加 通过指名道姓装饰给类下的方法
    @method_decorator(csrf_protect, name='post')
    class MyHome(views.View):
        #方式三:等于 类中所有方法添加 装饰器(且 csrf_exempt装饰器 只用该方式有效)
        @method_decorator(csrf_protect)
        def dispatch(self, request, *args, **kwargs):
            return super(MyHome, self).dispatch(request,*args,**kwargs)
        
        def get(self, request):
            return HttpResponse('hahah')
    
        @method_decorator(csrf_protect)  #方式一:指名道姓 直接给类下的方法上添加
        def post(self, request):
            return HttpResponse('嘿嘿嘿')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    注意:针对csrf_exe,pt只有方式三有效 针对其他装饰器上述三种方式都有效

    4、auth认证模块

    django执行数据库迁移命令之后会产生一个auth_user表
    该表可以配合auth模块坐用户相关的功能:注册、扽牢固、修改密码、注销····
    该表还是django admin后台管理默认的表

    django admin后台管理员账号创建
    python manage.py createsuperuser

    4.1、auth模块常见功能

    校验用户名是否正确

    from django.contrib import auth
    
    is_user_obj = auth.authenticate(request,username=username,password=password)
    
    • 1
    • 2
    • 3

    登录用户

    auth.login(request,user_obj)
    
    • 1

    判断用户是否登录

    print(request.user.is_authecticated) #返回布尔值
    
    • 1

    校验用户登录装饰器
    @login_required(login_url='/login/')

    from django.contrib.auth.decorators import login_required
    
    #登录函数
    def login(request):
        from django.contrib import auth
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            is_user_obj = auth.authenticate(request, username=username, password=password)
            if is_user_obj:
                auth.login(request, is_user_obj)  # 自动操作cookie和session
            # print(is_user_obj.password)
            # print(is_user_obj.pk)
    
    # 跳转局部配置 跳转至登录 网页
    @login_required(login_url='/login/')
    def index(request):
        return HttpResponse('index')
    
    #跳转全局配置 在配置文件中 直接配置
    LOGIN_URL = '/login/'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    修改密码
    校验旧密码是否正确

    request.user.check_password(old_password)
    
    • 1

    修改密码

    request.user.set_password(new_password)
    request.user.save()
    
    • 1
    • 2

    注销用户

    auth.logout(request)
    
    • 1

    创建用户
    create_user()创建普通用户
    create_superuser()创建管理员用户 必须要添加邮箱字段

    # 导入 该表的类
    from django.contrib.auth.models import User
    def reg(request):
        User.objects.create_user(username='kk',password=123)
        User.objects.create_superuser(username='ming',password='hong',email='888@163.com')
        return HttpResponse('注册功能')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.2、auth_user 表切换

    我们还想使用auth模块的方法并且扩展auth_user表字段

    在models 给表坐扩展

    from django.contrib.auth.models import AbstractUser
    
    
    class Userinfo(AbstractUser):
        """扩展 auth_user表中没有的字段"""
        # 创的时候 可以添加 参数使字段可以为空或 null=True
        phone = models.BigIntegerField()
        address = models.TextField()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    还需要 在 配置文件中 修改配置

    AUTH_USER_MODEL = 'app01.Userinfo'
    
    • 1

    5、基于django中间件涉及项目功能

    首先 需要创建 一个包 将所有功能都分为py文件 存放在包下 还需创建配置文件 启动文件

    在功能py文件中将功能封装为类 将功能使用 用相同的方法名 封装

    class QQ(object):
        def __init__(self):
            pass
    
        def send(self, content):
            print(f'qq发送消息:{content}')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    创建settings 配置文件
    将包下的功能类 的调用路径全部以字符串形式 封装为一个列表

    PACK_LIST = [
        'packet.qq.QQ',
        'packet.vx.VX',
        'packet.tt.TT',
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在启动文件中 调用包 就是调用包下的双下init 文件
    所以主要 的逻辑 都双下init.py文件下 通过 调用importlib模块 和settings文件
    import importlib

    from django.utils.decorators import method_decorator
    
    def re_by(func):
        def inner(request):
    
            import json
            try:
                request.data = json.loads(request.body)
                res=func(request)
                return res
            except Exception:
                request.data = request.POST
                return func(request)
        return inner
    
    
    
    @method_decorator(re_by,name='post')
    class BookView(View):
        def get(self, request):
            book_list = Book.objects.all()
            # queryset 对象 不能直接序列化 只能通过 for循环 一个个拼成列表套字典
            data_list = []
            for book in book_list:
                data_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
            return JsonResponse(data_list, safe=False, json_dumps_params={'ensure_ascii': False})
        
        def post(self, request):
            res = request.data
            print(res)
    
            return HttpResponse('成功')
    
    • 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
  • 相关阅读:
    设计模式学习笔记(二十二)解释器模式及其实现
    windows下部署nginx+PHP环境,连接SQL Server
    线段树杂谈
    CSSStyleSheet 对象(css 样式表)- 你不知道的有趣功能
    音频占用磁盘空间太多 需要把mp3音频转aac音频缩小占用空间 应该怎么操作?
    【vue】ant-design弹出框无法关闭和runtimecore提示isFucntion is not function的问题修复
    Open3D 进阶(18)整体最小二乘拟合平面
    647. 回文子串
    输入操作符重载(读写文件)
    Mac无法挂载exfat磁盘怎么办?
  • 原文地址:https://blog.csdn.net/weixin_71967396/article/details/126842336