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


    一:csrf跨站请求伪造

    1.前戏

    钓鱼网站:搭建一个和正常网站一模一样的网页,只是后端提交数据的时候,不会按照你输入的用户桩长,而是将钱转到钓鱼网站自己默认设置好的账号中去,导致自己的转账不知去向

    钓鱼网站的原理:搭建两个相同的前端页面,然后后端开设两个不同的端口,其中钓鱼网站的前端提交的地址设置为正确网站的地址

    2.什么是csrf跨站请求伪造?
    • 网站在给用户返回一个具有提交数据功能的页面的时候,会给这个页面加上一个唯一标识,当这个页面朝后端发送post请求的时候,
    • 后端会自动校验这一标识,如果标识不对,则直接拒绝(403frobbiden),如果标识正确,则正常执行执行
    3.form表单中的csrf操作:
    • 方法一:直接在前端页面的form表单中添加{% csrf_token %}
    <h1>我是一个正儿八经的网站h1>
    <form action="">
    {% csrf_token %}
    <p>username:<input type="text" name="username">p>
    <p>target_name:<input type="text" name="target_name">p>
    <p>money:<input type="text" name="money">p>
    <input type="submit">
    form>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    4.ajax中的csrf操作
    • 方法一:利用标签查找获取页面上随机字符串

    • 方法二:利用模板语法提供的快捷方式

    • 方法三:直接拷贝js代码,并应用到自己的html页面上

      • 1.创建静态文件夹static
      • 2.在文件夹中创建js文件夹
      • 3.在js文件夹中创建mysetup.js文件,将配置的代码粘贴到里面
      • 4.在settings.py中添加静态文件配置
      STATICFILES_DIRS = [
          os.path.join(BASE_DIR, 'static')
      ]
      
      • 1
      • 2
      • 3
      • 5.在项目文件中导入该js文件即可
      {% load static %}
      <script src="{% static 'js/mysetup.js' %}"></script>
      
      • 1
      • 2
    • 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
    <script>
        $('#d1').click( function () {
            $.ajax({
                url:'',
                type:'post',
                // 第一种方式:利用标签查找获取页面上随机字符串
                {#data: {"username": 'jason', "csrfmiddlewaretoken": $('[name=csrfmiddlewaretoken]').val()},#}
                // 第二种方式:利用模板语法提供的快捷方式
                {#data: {"username": 'jason', "csrfmiddlewaretoken": {{csrf_token}},#}
                // 第三种方式:直接拷贝js代码,并应用到自己的html页面上
    
                success: function () {
    
                }
            })
        })
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    二:csrf相关装饰器

    1.前提

    1.当整个网站默认都不校验csrf 但是局部视图函数需要校验 如何处理
    2.当整个网站默认都校验csrf 但是局部视图函数不需要校验 如何处理

    2.FBV中的装饰器
    • 装饰器1:csrf_protect 校验csrf
    • 装饰器2:csrf_exempt 不校验csrf
    from django.views.decorators.csrf import csrf_protect,csrf_exempt
    
    @csrf_exempt
    def home(request):
        return render(request, 'home.html')
    
    @csrf_protect
    def login(request):
        return render(request, 'login.html')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    3.CBV中的装饰器
    • 1.csrf_protect
    from django.utils.decorators import method_decorator
    from django import views
    
    # 方式二:指名道姓的添加
    @method_decorator(csrf_protect, name='post')
    class Myindex(views.View):
    
        # 方式三: 直接影响类中的所有方法
        def dispatch(self, request, *args, **kwargs):
            super(Myindex, self).dispatch(request, *args, **kwargs)
    
        # 方式1:直接指名道姓的添加
        @method_decorator(csrf_protect)
        def get(self, request):
            return HttpResponse('get页面')
    
        def post(self, request):
            return HttpResponse('post页面')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 2.csrf_exempt:只有方式3有效 针对其他装饰器上述三种方式都有效

    三:auth认证模块

    1.auth模块中的常见方法
    1.创建用户:
    • 创建普通用户:密码是不被加密的
    • 创建超级管理员:必须添加一个email参数
    from django.contrib.auth.models import User
    User.object.create_user(username, password)  # 创建普通用户,密码是没有被加密的
    User.object.create_superuser(username, password,email)  # 创建超级管理员用户
    
    • 1
    • 2
    • 3
    2.校验用户名和密码
    • authenticate方法
    from django.contrib import auth
    auth.authenticate(request,username,password)
    
    • 1
    • 2
    3.用户登录
    auth.login(request, user_obj)
    
    • 1
    4.判断用户是否登录
    request.user.is_authenticated
    
    • 1
    5.获取登录用户对象
    request.user
    
    • 1
    6.校验用户登录装饰器
    • 局部配置
    • 全局配置:配置到settings.py文件中
    from django.contrib.auth.decorators import login_required
    # 局部配置
    login_required(login_url='/login/')
    
    # 全局配置
    LOGIN_URL = '/login/'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    7.校验密码是否正确
    request.user.check_password(old_password)
    
    • 1
    8.修改密码
    • 切记:修改密码之后一定要保存
    request.user.set_password(new_password)
    request.user.save()
    
    • 1
    • 2
    9.注销登录
    auth.logout(request)
    
    • 1
    10.练习
    • urls.py
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # 登录
        url(r'^login/', views.login),
        # 登录之后的页面
        url(r'^home/', views.home),
        # 修改密码的页面
        url(r'^set_password/', views.set_password),
        # 注销账号
        url(r'^logout/', views.logout),
        # 注册用户
    	url(r'^register/', views.register),
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • views.py
    from django.contrib import auth
    from django.shortcuts import render, redirect, HttpResponse
    
    
    # Create your views here.
    
    
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            # 用户表中的数据校验
            # 表如何获取
            # 密码如何比对
            user_obj = auth.authenticate(request, username=username, password=password)
            # 1.自动查找auth_user标签
            # 2.自动给密码加密并比对
            # 3.必须同时传用户名和密码
    
            # 保存用户状态
            if user_obj:
                auth.login(request, user_obj)
                # 只要执行了该方法,你就可以在任何地方通过request.user获取到当前登录的用户对象
                return redirect('/home/')
    
        return render(request, 'login.html')
    
    
    from django.contrib.auth.decorators import login_required
    
    # @login_required  # # 全局配置
    # @login_required(login_url='/login/')  # 用户没登录的情况下,跳转到指定的页面  局部配置
    def home(request):
        """用户登录之后才可以访问的页面"""
        print(request.user)
        print(request.user.is_authenticated())  # 判断当前用户是否登录
        return HttpResponse('ok')
    
    # 设置密码
    @login_required
    def set_password(request):
        if request.method == 'POST':
            old_password = request.POST.get('old_password')
            new_password = request.POST.get('new_password')
            confirm_password = request.POST.get('confirm_password')
            if new_password == confirm_password:
                if request.user.check_password(old_password):
                    request.user.set_password(new_password)
                    request.user.save()
            return redirect('/login/')
        return render(request, 'set_password.html', locals())
    
    # 注销账号
    @login_required
    def logout(request):
        auth.logout(request)
        return redirect('/login/')
    
    
    from django.contrib.auth.models import User
    # 注册用户
    @login_required
    def register(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            # 创建普通用户
            # User.objects.create_user(username=username, password=password)
            User.objects.create_superuser(username=username, password=password, email='123@qq.com')
    
        return render(request, 'register.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
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    <form action="" method="post">
        <h1>登录h1>
        {% csrf_token %}
        <p>username:<input type="text" name="username">p>
        <p>password:<input type="text" name="password">p>
        <p><input type="submit" value="登录">p>
    form>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    <form action="" method="post">
        <h1>修改密码h1>
        {% csrf_token %}
        <p>username:<input type="text" name="username" disabled value="{{ request.user.username }}">p>
        <p>old_password:<input type="text" name="old_password">p>
        <p>new_password:<input type="text" name="new_password">p>
        <p>confirm_password:<input type="text" name="confirm_password">p>
        <input type="submit" value="确认">
    form>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    <form action="" method="post">
        <h1>注册h1>
        {% csrf_token %}
        <p>username:<input type="text" name="username">p>
        <p>password:<input type="text" name="password">p>
        <p><input type="submit" value="注册">p>
    form>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    四:auth_user表切换

    • 第一步:models.py中
    from django.contrib.auth.models import AbstractUser
    
        class Userinfo(AbstractUser):
            '''扩展auth_user表中没有的字段'''
            phone = models.BigIntegerField()
            desc = models.TextField()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 第二步:settings.py中
    AUTH_USER_MODEL = 'app01.Userinfo'
    
    • 1
    总结:
    • 1.如果继承了AbstractUser,那么在执行数据库迁移命令的时候,auth_user表就不会再被创建出来
    • 2.UserInfo表会创建,并且它里面包含auth_user表中所有的字段,并且还可以增加自己独有的字段
    • 3.在执行数据库迁移命令之前,不能存在已经创建好的auth_user表,如果存在,则直接换库
    • 4.新表中只能创建auth_user表中没有的字段
    • 5.必须在配置文件中声明:AUTH_USER_MODEL = ‘app01.UserInfo’

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

    第一步:先创建一个notify文件夹,在该文件夹中可以创建py文件,eg:wechat.py, qq.py, email.py,__ init__.py

    __ init__.py文件

    import settings
    import importlib
    
    def send_all(content):
        for path_str in settings.NOTIFY_LIST:
            moudel_path, class_name = path_str.rsplit('.', maxsplit=1)
            # 1.利用字符串导入模块
            module = importlib.import_module(moudel_path)
            # 2.利用反射获取类名
            cls = getattr(module, class_name)
            # 3.生成类对象
            obj = cls()
            # 4.利用鸭子类型直接调用send方法
            obj.send(content)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    email.py文件

    class Email(object):
        def __init__(self):
            pass  # 发送微信需要做的前期准备
    
        def send(self, content):
            print('邮箱通知:%s' % content)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    qq.py文件

    class QQ(object):
        def __init__(self):
            pass  # 发送微信需要做的前期准备
    
        def send(self, content):
            print('QQ通知:%s' % content)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    wechat.py文件

    class Wechat(object):
        def __init__(self):
            pass  # 发送微信需要做的前期准备
    
        def send(self, content):
            print('微信通知:%s' % content)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    第二步:在项目根目录下还需要建两个py文件,分别是:start.py和settings.py

    start.py文件

    import notify
    notify.send_all('下课了')
    
    • 1
    • 2

    settings.py

    NOTIFY_LIST = [
        'notify.email.Email',
        'notify.qq.QQ',
        'notify.wechat.Wechat'
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    新知同享 | AI 开发广泛应用,高效构建
    Vuex模块化(modules)与namespaced(命名空间)的搭配
    程序员是怎么把自己从高端人士变成民工的
    见证云力量|飞马网技术沙龙“云计算专场”圆满结束
    计算机组成原理
    Java策略模式之总有你想不到的知识
    【动画进阶】极具创意的鼠标交互动画
    细胞膜包裹精氨酸脱亚胺酶脂质纳米粒/融合细胞膜包裹尿酸酶/过氧化氢酶脂质纳米粒的研究
    论文阅读之Dynamic Routing Between Capsules(2017)
    温控仪的工作原理
  • 原文地址:https://blog.csdn.net/Yydsaoligei/article/details/126835404