zoukankan      html  css  js  c++  java
  • 10.Django -- csrf -- 文件上传

    1.csrf

    1.1 简介:

    CSRF(Cross-site request forgery),中文名称:跨站请求伪造.
    攻击者通过HTTP请求江数据传送到服务器,从而盗取回话的cookie。盗取回话cookie之后,攻击者不仅可以获取用户的信息,还可以修改该cookie关联的账户信息。
    

    1.2 django的csrftoken防御机制

    1.form 通过csrf认证:

    settings.py中

    MIDDLEWARE = [
    	# csrf 认证: 对所有的给后台发送的post和put请求进行了csrftoken认证
        'django.middleware.csrf.CsrfViewMiddleware', #以后不用注释了
        ]
    

    login.html

    <body>
    
    <form action="" method="post">
        {% csrf_token %}  # form表单中加入
        # 浏览器解析为隐藏的input标签: <input type="hidden" name="csrfmiddlewaretoken" value="随机字符串">
        用户名: <input type="text" name="username">
        密码: <input type="password" name="password">
        <input type="submit">
    </form>
    </body>
    
    2.ajax通过csrf认证:
    方式1: 主要是向后台发送token值

    login.html --- body中添加{% csrf_token %} -- ajax中通过属性获取token值,data把token键值对提交到后台数据

    <body>
    
        {% csrf_token %}  <!--添加csrf认证--> 
        
        用户名:<input type="text" id="username">
        密码:<input type="password" id="pwd">
        <span class="error"></span> <!--如果密码不对,用来存放错误信息-->
        <button id="btn">ajax提交数据</button>
    
    </body>
    
    <script src="{% static 'jquery.js' %}"></script>
    <script>
        //ajax发送请求提交数据
        $('#btn').click(function (){ //触发点击事件
    
            var token = $('[name=csrfmiddlewaretoken]').val() //通过属性,获取csrf的token值
            
            var user = $('#username').val() //通过id获取标签中数据
            var pwd = $('#pwd').val()
    
            $.ajax({
                url:'/ajax_login/',//发送请求路径,往本网站发可以用相对路径
                type:'post', //请求方法,post或get小写
                data:{username:user,password:pwd,csrfmiddlewaretoken:token}, //向后台提交的数据,添加token键值对
    
                // 2.当状态码为4xx(请求错误),5xx(服务端错误)等时,那么ajax会加工响应数据并传递给error对应的函数
                
                success:function (res){
                    alert('登陆成功!!')
                    location.href = '/home/' //网页跳转到home路径,使用的浏览器的机制
                },
                error:function (error){ //后台返回更改4xx的状态码时,执行该语句
                    console.log('error>>>',error);
                    if (error.status === 400){
                        $('.error').text('用户名或密码有误!'); //向span标签添加错误信息
                        alert('用户名或密码有误')
                    }
                },
            })
        })
    
    </script>
    
    
    方式2: 主要是向后台发送token值
    	        $.ajax({
                url:'/ajax_login/', // 请求路径  相对路径
                type:'post',  // 请求方法,小写
                {#data:{a:1,b:2}, // 请求携带数据#}
                data:{username:uname, password:pwd,csrfmiddlewaretoken:'{{csrf_token}}'},
                } //{{}}直接在ajax发送值,不用提前获取值了  
    
    方式3:通过cookie完成认证
    cookie中: csrftoken:asdf随机字符串
    post请求数据: csrfmiddlewaretoken:asdf随机字符串
    请求头键值对: X-CSRFToken:asdf随机字符串
    认证顺序:
       先认证请求数据部分,如果没有token数据,继续找请求头键值对,如果它与cookie中的csrftoken值相同,同样可以通过认证
    

    下载引入jquery.cookie.js文件

    百度bootcdn,Bootstrap 中文网开源项目免费 CDN 加速服务
    搜索jquery.cookie,把代码复制到jquery.cookie.js中
    HTML中引入:
    	<script src="{% static 'jquery.cookie.js' %}"></script>
    取cookie值:$.cookie('csrftoken')
    设置cookie值:$.cookie('xxx','ooo')
    
       {% csrf_token %}
        用户名:<input type="text" id="username">
        密码:<input type="password" id="pwd">
        <span class="error"></span> <!--如果密码不对,用来存放错误信息-->
        <button id="btn">ajax提交数据</button>
    
    </body>
    
    <script src="{% static 'jquery.js' %}"></script>
    <script src="{% static 'jquery.cookie.js' %}">
        // 引入jquery.cookie.js文件
    </script>
    <script>
        //ajax发送请求提交数据
        $('#btn').click(function (){ //触发点击事件
    
            {#var token = $('[name=csrfmiddlewaretoken]').val() //通过属性,获取csrf的token值#}
            var user = $('#username').val() //通过id获取标签中数据
            var pwd = $('#pwd').val()
    
            $.ajax({
                url:'/ajax_login/',//发送请求路径,往本网站发可以用相对路径
                // url:'http://127.0.0.1:8000/ajax_login/',//往其他网站发只能用绝对路径
                type:'post', //请求方法,post或get小写
                {#data:{username:user,password:pwd,csrfmiddlewaretoken:token}, //向后台提交的数据#}
                data:{username:user,password:pwd,}, //向后台提交的数据
    
                header:{ //ajax加请求头键值对
                    "X-CSRFToken": $.cookie('csrftoken')//获取cookie中csrftoken值
                },
    
                // 2.当状态码为4xx(请求错误),5xx(服务端错误)等时,那么ajax会加工响应数据并传递给error对应的函数
    
                success:function (res){
                    alert('登陆成功!!')
                    location.href = '/home/' //网页跳转到home路径,使用的浏览器的机制
                },
                error:function (error){ //后台返回更改4xx的状态码时,执行该语句
                    console.log('error>>>',error);
                    if (error.status === 400){
                        $('.error').text('用户名或密码有误!'); //向span标签添加错误信息
                        alert('用户名或密码有误')
                    }
    
                },
            })
        })
    

    2.上传文件

    2.1 form表单上传文件

    请求头键值对:
    	Content-Type: application/x-www-form-urlencoded
    规定的是请求数据部分的数据格式:								csrfmiddlewaretoken=V7TlcirtILCg70HhBmJwlBhhywOiQ9UYN2LLrrGN9TceOJQI37ysJFuPOjxHTHRl&uname=asdf&pwd=123
     
    问题是文件数据不能通过这个格式发送,文件数据需要分片发送,换消息格式
    	Content-Type: multipart/form-data  # 片段数据格式
    更改文件上传格式:
    	<form action="" method="post" enctype="multipart/form-data">
    

    路由:urls.py

    from app01 import views
    urlpatterns = [
        url(r'^upload/', views.upload),
    ]
    

    视图:views.py

    def upload(request):
    
        if request.method == 'GET':
            return render(request, 'upload.html')
        else:
            print(request.POST)
            #1. 没指定上传格式:
            #<QueryDict: {'csrfmiddlewaretoken': ['随机字符串'], 'uname': ['chao'], 'pwd': ['123'], 'avatar': ['1.jpeg']}>
            # 'avatar': ['1.jpeg'] -- 只是文件名称,没有文件数据
    
            #2. 如果请求的数据格式是multipart/form-data,那么django会将文件数据单独处理,并且保存到request.FILES对象中
            #<QueryDict: {'csrfmiddlewaretoken': ['随机字符串'], 'uname': ['chao'], 'pwd': ['123']}> 
           
        	print(request.FILES) 
            #<MultiValueDict: {'avatar': [<InMemoryUploadedFile: 1.jpeg (image/jpeg)>]}>
            # 内存文件句柄对象
           
        	file_obj = request.FILES.get('avatar')#获取文件对象 
            print(file_obj.name)  # 获取文件名称
    
            # 两种方式都可以上传文件 
            # 方式1 : 以
    分段上传数据(如果文件没有
    ,就一次性读取数据了,最好使用方式2方法)
            with open(file_obj.name, 'wb') as f: 
                #相对路径会从项目根目录开始
                 for i in file_obj:  # 以
    进行循环
                     f.write(i)
            
            # 方式2   自行控制一次性读取数据的大小
            with open(file_obj.name, 'wb') as f:
                for j in file_obj.chunks(): # 默认65536B
                # for j in file_obj.chunks(chunk_size=数字): # 自己设置传输数据大小,或chunks(数字)也可以,就一个参数
                    f.write(j)
    
            return render(request, 'upload.html')
    

    templates目录下upload.html

    <body>
    <form action="" method="post" enctype="multipart/form-data"> <!--指定上传文件格式-->
        {% csrf_token %}
    
        用户名:<input type="text" name="uname">
        密码:<input type="password" name="pwd">
        头像:<input type="file" name="avatar">
        <input type="submit">
    
    </form>
    
    </body>
    

    2.2 ajax上传文件

    路由urls.py和视图views.py和form表单上传文件一样.

    templates目录下upload.html

    {% load static %} <!--引入静态文件-->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        用户名: <input type="text" name="uname" id="uname">
        <br>
        密码: <input type="text" name="pwd" id="pwd">
        <br>
    {#    头像: <input type="file" name="avatar" id="avatar" multiple>#} <!--multiple多选-->
        头像: <input type="file" name="avatar" id="avatar">
        <button id="btn">上传</button>
    
    </body>
        
    <script src="{% static 'jquery.js' %}"></script> <!--引入jquery文件-->
    
    <script>
        $('#btn').click(function () {
            //获取input数据
            var uname = $('#uname').val();
            var pwd = $('#pwd').val();
            var formdata = new FormData(); // ajax上传文件必须借助formdata对象
            // FormData -- 将请求头键值对改成了content-type:mutiplepart/form-data
            var file_obj = $('#avatar')[0].files[0];  // 获取的浏览器中上传的文件对象
            
    		//向formdata添加数据
            formdata.append('uname', uname);
            formdata.append('pwd', pwd);
            formdata.append('avatar', file_obj);//文件对象名不变
            formdata.append('csrfmiddlewaretoken', '{{ csrf_token }}'); # 通过scrf认证
    
            $.ajax({
                url:'/upload/',
                type:'post',
                data:formdata, 
    
                // ajax上传文件必须配置的两个参数
                processData: false ,    // 不处理加工数据
                contentType: false,    // 不设置内容类型
    
                success:function (res) {
                    console.log(res);
                }
            })
        })
    </script>
    </html>
    
  • 相关阅读:
    table常用功能总结
    oracle中number类型的数据使用as string 得到的值为null
    Oracle连接超时
    VS重新生成后仍然执行旧代码
    .NET 环境中使用RabbitMQ
    使用CLR Function代替T-SQL函数,优化检索效率
    SQL Server CLR 使用 C# 自定义存储过程和触发器
    OrderBy排序和IComparer的使用
    System.net.mail 使用ssl发送邮件失败
    C#利用CDO.Message发送邮件
  • 原文地址:https://www.cnblogs.com/jia-shu/p/14589836.html
Copyright © 2011-2022 走看看