django:csrf_token和文件上传、中间件

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • Crsf介绍
  • django实现csrf_token认证
    • form表单实现csrf_token认证
    • ajax实现csrf_token认证
    • 关于csrf的一些理解
    • csrf_token校验
  • django实现文件上传
    • form表单实现文件上传
    • ajax实现文件上传
    • 文件上传的views.py(form表单和ajax都用这套视图函数)
  • 中间件:Middleware
    • 中间件概念
    • django请求的生命周期
    • 中间件可以定义的5个方法
    • 自定义中间件的流程
    • 关于中间件的方法的执行顺序
      • process_request和process_response
      • process_request和process_response + process_view
      • process_request和process_response + process_view + process_exception


Crsf介绍

csrf:跨站请求伪造。攻击者通过HTTP请求将数据传送到服务器,从而盗取会话的cookie。

盗取会话cookie之后,攻击者不仅可以获取用户的信息,还可以修改该cookie关联的账户信息。

django实现csrf_token认证

form表单实现csrf_token认证

直接写上{% csrf_token %}

<form action="">
    {% csrf_token %}
    <input type="text" name="username">
    <input type="submit">
</form>

ajax实现csrf_token认证

方式1

在html里,写了个{% csrf token %},其实翻译过来,就是生成了个input标签

input标签是这个样子的:

<input type="hidden" name="csrfmiddlewaretoken" value="BzOzpsnD1zqiZMm3jp1TdW2knEI2BvxwEXrsJbZTIdqL1Kj6P7o4pN38sTn8K5ia">

我们在js中获取属性name为csrfmiddlewaretokan的那个input标签的value的值

然后通过ajax中的data传递过去
// 方式1 
<input type="text" name="username">
<button id="btn">确认button>

{% csrf_token %}

<script src="{% static 'plugins/jquery.js' %}">script>
<script>

    var uname = $('#username').val();
    // 方式1
    // 通过input标签的name属性获取csrfmiddlewaretoken的值
    var token = $('[name="csrfmiddlewaretoken"]').val();

    $.ajax({
        url:'/ajax_login',
        type:'post',
        data:{uname:uname,csrfmiddlewaretoken:token}
        success:function (res) {
            alert(res)
        }
    })
script>

方式2
这种方式和方式1差不多,只是在data中csrfmiddlewaretoken的值 变成了{{ csrf_token }}

在django中可以通过双大括号取值

	$.ajax({
            type: 'post',  // 请求方法.
            url: '/login/',
            // {{ csrf_token }}拿到是{% csrf_token %}生成的input标签的那个value属性的token值
            data: {xname: uname, pwd: password, csrfmiddlewaretoken: '{{ csrf_token }}'},
            success: function (res) {
                console.log('success', res);

            },
            error: function (error) {
                console.log('error>>>>>', error);
                $('#ajax_error').text(error.responseText);

            }

        })

方式3
data里不在写csrfmiddlewaretoken,而是写在ajax中的header里

这种方法的csrf认证是写在cookie里的 cookie里的csrf和input标签里value的csrf是不一样的

方式3 添加请求头键值对,键必须叫做:'X-CSRFToken',值是cookie中的token值
	$.ajax({
            type: 'post',  // 请求方法.
            url: '/login/',

            data: {xname: uname, pwd: password},
            headers:{  // 设置请求头键值对
                'X-CSRFToken':$.cookie('csrftoken'),
            },
            success: function (res) {

                console.log('success', res);

            },
            error: function (error) {
                console.log('error>>>>>', error);
                $('#ajax_error').text(error.responseText);

            }
        })

关于csrf的一些理解

'''
1.本质
我们在钓鱼网站的页面 针对对方用户 只给用户提供一个没有name属性的普通input框
然后我们在内部隐藏一个已经写好的name和value的input框

2.如何规避跨站攻击问题
    csrf跨站请求伪造校验
        网站在给用户返回一个具有提交数据的页面的时候会给这个页面加一个唯一标识
        当这个页面朝后端发送post请求的时候,后端会先校验唯一标识
            如果唯一标识不对,直接拒绝(403 forbidden)
            如果成功则正常执行
两个网站请求两个页面,两个网站分别返回两个页面,两个页面长的一模一样
当页面提交post请求的时候

**:网站在返回页面的时候,给每个页面都携带了一个随机标识过去的
    两个网站请求两个页面 
        客户端向服务端发送请求 
        服务端返回页面给客户端,在返回页面的时候是带了一个随机标记过去的
            比如说正常网站请求页面,网站返回一个页面,并携带随机标识33333
            钓鱼网站请求页面,网站返回一个页面,并携带随机标识44444(因为标识唯一,所以两个标识绝对不相同)
        客户端(浏览器)有input框,输入数据提交,这个时候客户端向服务端发送POST请求
        服务端会验证你发过来的post请求里,有没有唯一标记33333
        而钓鱼网址他的唯一标识,是钓鱼网址的服务端给它发的44444
        而当正常网址/钓鱼网址提交post请求时,服务端会验证你的唯一标识是否是他之前给客户端的那个
            如果唯一标识正确,就可以向后台提交数据
            如果唯一标识错误,就会把它forbidden 403掉,不能向后台提交数据
'''

csrf_token校验

# form表单如何符合校验
在form表单里面添加{% csrf_token %}
'''
当客户端向服务端发送请求时,{% csrf_token %}会解析成一个input标签
这个input标签携带了那个唯一标识
当我点击提交按钮的时候,这个唯一标识会被提交到后端
'''
# ajax如何符合校验
'''
第一种:利用标签查找获取页面上的随机字符串
    在ajax的data中 键值必须叫csrfmiddlewaretoken 值通过属性选择器去获取name=csrfmiddlwaretoken的input标签的value值,也就是那个唯一标识串
    data:{uname:uname,csrfmiddlewaretoken:$('[name="csrfmiddlewaretoken"]').val()}
    
第二种:直接利用模板语法提供的快捷书写
    {{  }}语法来写
    data:{uname:uname,csrfmiddlewaretoken:'{{ csrf_token }}'},
    
第三种:写在header里
      headers:{
            'X-CSRFToken':$.cookie('csrftoken')

第四种:引入一个js文件,其他的都不用写了

	jquery操作cookie,下载jquery.cookie.js文件
    	http://plugins.jquery.com/cookie/
		https://www.bootcdn.cn/jquery-cookie/
	引入使用
		
		
'''

django实现文件上传

form表单实现文件上传

从html获取数据,在js中获取定义成变量
然后放到formdata中
在ajax中的data直接传formdata即可,注意加processData和ContentType

用户名:<input type="text" name="username" id="username">

头像:<input type="file" name="avatar" id="avatar">
<button id="ajax_btn">上传</button>

<script>
    $('#ajax_btn').click(function () {

        var uname = $('#username').val();
        var file_obj = $('#avatar')[0].files[0]; // 文件对象

        var formdata = new FormData(); // 创建formdata对象,用来获取表单数据,方便进行提交数据
        formdata.append('username',uname); // 获取input框输入的用户名
        formdata.append('csrfmiddlewaretoken','{{ csrf_token }}'); // 获取csrf_token值
        formdata.append('avatar',file_obj); // 获取用户上传的文件对象


        $.ajax({
            url:'/login/',
            type:'post',
            data:formdata, 
            processData: false ,    // 不处理数据
            contentType: false,    // 不设置内容类型
            success:function (res) {
                console.log(res);
            }
        })
    })
</script>

ajax实现文件上传

从html获取数据,在js中获取定义成变量
然后放到formdata中
在ajax中的data直接传formdata即可,注意加processData和ContentType

用户名:<input type="text" name="username" id="username">

头像:<input type="file" name="avatar" id="avatar">
<button id="ajax_btn">上传</button>

<script>
    $('#ajax_btn').click(function () {

        var uname = $('#username').val();
        var file_obj = $('#avatar')[0].files[0]; // 文件对象

        var formdata = new FormData(); // 创建formdata对象,用来获取表单数据,方便进行提交数据
        formdata.append('username',uname); // 获取input框输入的用户名
        formdata.append('csrfmiddlewaretoken','{{ csrf_token }}'); // 获取csrf_token值
        formdata.append('avatar',file_obj); // 获取用户上传的文件对象

        $.ajax({
            url:'/login/',
            type:'post',
            data:formdata, 
            processData: false ,    // 不处理数据
            contentType: false,    // 不设置内容类型
            success:function (res) {
                console.log(res);
            }
        })
    })
</script>

文件上传的views.py(form表单和ajax都用这套视图函数)

通过request读取在前端js定义好的file_obj

然后通过文件对象.name 取出文件名 为接下来with open操作做准备

with open(文件名…)打开文件

for循环文件对象 将文件内容写入其他地方

def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    else:
        file_obj = request.FILES.get('avatar')
        name = file_obj.name
        with open(name, 'wb') as f:
            # 方式1
            # for i in file_obj:  # \r\n

            # 方式2
            # for i in file_obj.chunks():  # \r\n
            for i in file_obj.chunks():  # \r\n  读取65536B
                f.write(i)
        return HttpResponse('ok')

中间件:Middleware

中间件概念

1.中间件是介于request与response处理之间的一道处理过程。

2.如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,
这些都可以通过中间件来实现。

3.可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。

4.说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,

5.中间件本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

django请求的生命周期

django:csrf_token和文件上传、中间件_第1张图片

中间件可以定义的5个方法

中间件可以定义五个方法,分别是:(主要的是process_request和process_response)

process_request(self,request)

process_view(self, request, view_func, view_args, view_kwargs)

process_template_response(self,request,response)

process_exception(self, request, exception)

process_response(self, request, response)

以上方法的返回值可以是None或一个HttpResponse对象

  1.如果是None,则继续按照django定义的规则向后继续执行。

  2.如果是HttpResponse对象,则直接将该对象返回给用户。

当用户发起请求的时候会依次经过所有的的中间件

  1.这个时候的请求是process_request

  2.最后到达views的函数中,views函数处理后,

  3.在依次穿过中间件,这个时候是process_response,最后返回给请求者。

django:csrf_token和文件上传、中间件_第2张图片

自定义中间件的流程

1.在应用下先创建一个文件夹,名字随便起。比如叫mymiddleware

2.在mymiddleware文件夹下创建一个py文件。比如叫mid.py

3.在mid.py写上如下内容

from django.utils.deprecation import MiddlewareMixin

class Auth(MiddlewareMixin):  # 类名随意,继承MiddlewareMixin
    # 如果想对请求做一些统一处理,那么就定义process_request方法
    def process_request(self,request):
        print('请求来啦!!!快看!!!!')
        
    def process_response(self,request,response):
        # response 视图响应回来的响应对象
        print('请求走啦!!!慢走!!!!')
        return response    # 注意!一定要些return response

4.在setting.py文件中做如下配置

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'app01.mymiddlewares.xx.Auth',  #将中间件类的路径写到这里
]
'''
注意:要把自定义中间件写在最后一行,因为中间件的执行顺序是由上到下执行的
如果第一个中间件执行不通,后面的中间件根本就没有办法执行
'''

关于中间件的方法的执行顺序

process_request和process_response

顺序:请求1→请求2→响应2→响应1
django:csrf_token和文件上传、中间件_第3张图片

process_request和process_response + process_view

顺序:请求1→请求2→url路由→视图1→视图2→视图函数→响应2→响应1
django:csrf_token和文件上传、中间件_第4张图片
如果在中间件1中的process_view写了return HttpResponse方法后,执行过程是这样的
django:csrf_token和文件上传、中间件_第5张图片

process_request和process_response + process_view + process_exception

1.如果视图函数时正确的,执行流程如下所示
django:csrf_token和文件上传、中间件_第6张图片
2.如果视图函数错误,执行流程如图所示
django:csrf_token和文件上传、中间件_第7张图片

你可能感兴趣的:(python笔记,中间件,python,django)