zoukankan      html  css  js  c++  java
  • Django 11

    功能配置设计

    • 实现类似于的django中settings.py中的中间件的字符串, 注释某个字符串, 使得相应的功能失效

    • importlib 模块

    # 可以利用 特定格式的字符串路径 导入模块
    import importlib
    path_str = 'lib.test'
    mod = importlib.import_module(path_str)  # from lib import test
    
    '''
    文件结构
    notify
    	__init__.py
    	email.py
    	msg.py
    	wechat.py
    settings.py
    start.py	
    '''
    # __init__.py
    import settings
    import importlib
    
    
    def send_all(content):
        for path_str in settings.NOTIFY_LIST:
            module_path, class_name = path_str.rsplit('.', maxsplit=1)
            # 拿到文件对象
            mod = importlib.import_module(module_path)  # from notify import email/msg/wechat
            # 利用反射获取文件对象中的类
            cls = getattr(mod, class_name)
            # 实例化对象
            obj = cls(content)
            # 发送通知 (鸭子类型思想, 不管你是什么对象, 都有send方法)
            obj.send()
    
    # email.py
    class Email(object):
        def __init__(self, content):
            self.content = content
    
        def send(self):
            print(f'邮箱通知:{self.content}')
            
    # msg.py
    class Msg(object):
        def __init__(self, content):
            self.content = content
    
        def send(self):
            print(f'短信通知:{self.content}')
            
       
    # wechat.py
    class WeChat(object):
        def __init__(self, content):
            self.content = content
    
        def send(self):
            print(f'微信通知:{self.content}')
    
    
    
    # settings.py 
    NOTIFY_LIST = [
        'notify.email.Email',
        'notify.msg.Msg',
        'notify.wechat.WeChat',
    ]
    
    # start.py
    from notify import *
    
    if __name__ == '__main__':
        send_all('非常高兴的通知大家, 本周六加班')
        
        
    '''
    邮箱通知:非常高兴的通知大家, 本周六加班
    短信通知:非常高兴的通知大家, 本周六加班
    微信通知:非常高兴的通知大家, 本周六加班
    '''
    

    跨站请求伪造CSRF

    什么是CSRF

    什么是跨站请求伪造呢? 举一个简单的钓鱼网站的例子

    我们对照着某银行的页面写一个一模一样的页面, 然后将用户 "钓" 到我们这个页面上进行转账操作

    用户输入用户名, 密码, 对方账户, 以及转账金额, 提交

    然后我们利用事先写好的代码将"对方账户"改成我们自己的账户

    然后再将请求提交给某银行原页面对应的接口

    这样用户就默默的把钱转到我们账户上了...

    • 就是仿照着某个网站页面对后端提交数据的形式, 对其后端提交请求

    如果实现CSRF

    • 用户输入"对方账户" 的input标签, 不设置 name 属性, 因此后端就获取不到对应的数据
    • 利用一个隐藏的input标签, 设置 name 属性, 默认值是我们自己的账户
    • 这样后端就只能获取到隐藏input标签携带的值了
    {#向真实网站接口提交请求#}
    form action="http://127.0.0.1:8000/transfer/" method="post">
        <p>username <input type="text" name="username"></p>
    
     	{#用户实际需要输入的标签,没有name属性#}
        <p>target_account<input type="text"></p>
    
    	{#隐藏的标签, 有name属性和默认值#}
        <p><input type="text" value="bigb" name="target_account" style="display: none"></p>
    
        <p>money<input type="text" name="money"></p>
        <input type="submit">
    </form>
    

    如何避免CSRF

    • 解决思路: 只处理自己网页发送的post请求--->如何确定post请求来自自己的网页

      ​ --->在返回html页面中的form表单中添加一个隐藏的input框, 携带一个随机字符串

      ​ --->后端中间件通过这个随机字符串来判断是否是本网站发送的请求

    • form表单

    {#直接在form表单中添加 {% csrf_token %} 即可#}
    <form action="" method="post">
        {% csrf_token %}
        <p>username <input type="text" name="username"></p>
        <p>target_account<input type="text" name="target_account"></p>
        <p>money<input type="text" name="money"></p>
        <input type="submit">
    </form>
    
    {#然后我们在前端检查代码, 会发现多了个隐藏的input标签#}
    <input type="hidden" name="csrfmiddlewaretoken" value="eYT1yNAroJidl3qjDSLSe3U2o0OTQXjD8PcSb2crNDTQijAGjRHX7ual6Y9bLg4D">
    
    • ajax
    {#方式一: 将这个随机字符串添加到ajax向后端提交的data当中即可#}
    {% csrf_token %}
    <script>
        $('#d1').click(function () {
            $.ajax({
                url: '',
                type: 'post',
                
                //方式一: 利用标签的name属性查找标签并获取对应的随机字符串
                data:{'username':'bigb', 'csrfmiddlewaretoken':$('input[name='csrfmiddlewaretoken']').val()}
                
                 //方式二: 'csrfmiddlewaretoken':'{{ csrf_token }}'
                data:{'username':'bigb', 'csrfmiddlewaretoken':'{{ csrf_token }}'}
                success: function (data) {   
                }
            })
        })</script>
    
    
    
    {#方式二: 将如下代码放入一个静态js文件中, 再在html文件引入即可#}
    //获取
    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);
            }
        }
    });
    

    CSRF相关的两个装饰器

    • 导入: from django.views.decorators.csrf import csrf_exempt, csrf_protect

    • csrf_exempt: 该视图函数对应的页面不做csrf校验

    • csrf_protect: 该视图函数对应的页面进行csrf校验

    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    
    @csrf_exempt  # 不校验
    def index(request):
        return HttpResponse('index')
    
    @csrf_protect  # 校验
    def index(request):
        return HttpResponse('index')
    
    • 在CBV上加装这两个装器
      • csrf_exempt只能给dispatch方法装才能生效
      • csrf_protect怎么装都可以
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    
    class MyIndex(views.View):
        @method_decorator(csrf_exempt)  # csrf_exempt只能给dispatch方法装才能生效
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request, *args, **kwargs)
        
        def get(self, request):
            renturn render(request, 'index.html')
            
        @method_decorator(csrf_protect)  # csrf_protect三种方法都可以     
        def post(self, request):
            return HttpResponse('index')
    

    auth模块

    常用方法

    • 创建管理员用户
    #命令行输入 : python manage.py makesuperuser
    
    • 常用方法
    # 1.创建用户(注册)
    	# 导入模块
        	from django.contrib.auth.models import User
        # 创建普通用户 creatr_user
        	User.objects.create_user(username=username, password=password)
        # 创建管理员用户 creater_superuser
        	User.objects.create_superuser(username=username, password=password, email=email)
     
    
    # 2.校验用户名和密码是否正确(登录)
    	# 导入模块
        	from django.contrib import auth
        # 必须传入username和password, 返回用户对象
             user_obj = auth.authenticate(request, username=username, password=password)
                if user_obj:
                    return HttpResponse('登录成功!')
                else:
                    return HttpResponse('密码或用户错误!')
            
    # 3.保存用户状态(session)
        # 执行该代码后, 后面就可以通过 request.user 获取当前登录的用户对象
        	auth.login(request, user_obj)
        
    # 4.判断用户是否登录
    	request.user.is_authenticated()
        
    # 5.校验原密码是否正确(修改密码时需要先输入原密码) 
    	request.user.check_password(old_password)
        
    # 6.修改密码
    	request.user.set_password(new_password)
        
    # 7.注销
    	auth.logout(request)
        
    # 8. 登录认证装饰器
    	# 导入模块
        	from django.contrib.auth.decorators import login_required
        # 局部配置跳转地址
        	@login_required(login_url='/login/')
            def index(request):
                return HttpRespone('index')
        # 全局配置配置跳转地址
        	# 在settings.py中配置
            LOGIN_URL = /'login'/
            
            @login_required
            def index(request):
                return HttpRespone('index')   	 
    

    扩展auth_user表中的字段

    # 1.利用一对一表关系扩展字段
    	class UserDetail(models.Model):
        	phone = models.CharField(max_length=11)
        	addr = models.CharField(max_length=255)
    		
        	user = models.OneToOneField(to='User')
            
            
    # 2.利用面向对象的继承新建一个表, 替换掉原来的User表
    	from django.contrib.auth.models import AbstractUser
        
    	# 继承了AbstracterUser中所有的字段
    	class UserInfo(AbstractUser):  
        # 扩展字段
        phone = models.CharField(max_length=11)
        addr = models.CharField(max_length=255)
        
        # 需要在settigs.py中将默认表指定为UserInfo
        AUTH_USER_MODEL = 'app01.Userinfo'  # 应用名.表名
    
  • 相关阅读:
    洛谷 P6622
    洛谷 P6619
    LOJ 3188
    CF::Gym 102174G
    eJOI2017~2019
    洛谷 P6313
    洛谷 P6305
    JSOI2020 酱油记
    洛谷 P6234
    CodeForces 1334F
  • 原文地址:https://www.cnblogs.com/bigb/p/11992979.html
Copyright © 2011-2022 走看看