Django入门到放弃之CSRF_TOKEN


1.django解决csrf攻击方法

django使用中间件:django.middleware.csrf.CsrfViewMiddleware解决csrf攻击

form表单使用:

 -在form表单中 {% csrf_token%}

ajax提交

 方式一:放到data中
     $.ajax({
            url: '/csrf_test/',
            method: 'post',
            data: {'name': $('[name="name"]').val(),
                'password': $('[name="password"]').val(),
                'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()
            },
            success: function (data) {
                console.log('成功了')
                console.log(data)

            },
            error: function (data) {
                console.log('xxxxx')
                console.log(data)

            }
        })
        方式二:放到data中
        'csrfmiddlewaretoken':'{{ csrf_token }}'
        方式三:放到头中
        	headers:{'X-CSRFToken':'{{csrf_token}}'},
        

2.全局使用,局部禁csrf

# 全局启用,局部禁用(中间件不能注释,这个视图函数,已经没有csrf校验了)
 @csrf_exempt
 def csrf_test(request):
     if request.method=='GET':
         return render(request,'csrf_test.html')
     else:
         name=request.POST.get('name')
         password=request.POST.get('password')
         print(name)
         print(password)
         return HttpResponse('登录成功')

3.全局禁用,局部使用csrf

@csrf_protect
def csrf_test(request):
    if request.method=='GET':
        return render(request,'csrf_test.html')
    else:
        name=request.POST.get('name')
        password=request.POST.get('password')
        print(name)
        print(password)
        return HttpResponse('登录成功')

古怪的使用方式,在urls.py中

path('csrf_test/', csrf_exempt(views.csrf_test))

5.代码示例

登录认证中间件

# (没有登录就可以访问:login,home,           登录后才能访问:order,userlist,logout)

middlewares.py

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse,redirect

class LoginAuth(MiddlewareMixin):

    def process_request(self, request):
        exclude_url = ['/login/']
        res = request.session.get('is_login')
        request_path = request.get_full_path()

        # 如果没有登录并且访问的不是login路径,则获取之前的访问路径

        if (not res) and (request.path not in exclude_url) :
            login_path =  reverse ('login')
            return redirect('%s?returnUrl=%s'%(login_path,request_path))

        # 如果已经登录并且访问的是login路径,则提示注销后再登录
        elif res and (request.path in exclude_url):
            return HttpResponse('您当前已经登录,请注销后重新登录')


view.py
def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    else:
        print('login函数')
        username = request.POST.get('username')
        password = request.POST.get('password')

        user_obj = models.User.objects.filter(name=username, password=password)
        if user_obj:
            request.session['is_login'] = True
            path = request.GET.get('returnUrl')
            if path:
                obj = redirect(path)
            else:
                obj = redirect('login')
            return obj
        else:
            return HttpResponse('用户或密码错误')

获取前端各编码提交数据存储到request.data

无论前端是什么编码的请求,后端视图函数都有request.data
前端代码:
get提交 urlencoded编码

<div class="container-fluid">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h1 class="text-center">登录界面</h1>
            <form action="" method="get">
                {% csrf_token %}
                <div class="form-group">
                    <label for="id_username">用户名:</label>
                    <input type="text" class="form-control" id="id_username" placeholder="用户名"
                           aria-describedby="basic-addon1" name="username">
                </div>
                <div class="form-group">

                    <label for="id_password">密码:</label>
                    <input type="password" class="form-control" id="id_password" placeholder="密码"
                           aria-describedby="basic-addon1" name="password">
                </div>
                <div class="form-group">

                    <input class="btn btn-danger" type="submit">
                </div>
            </form>

        </div>

    </div>
</div>

post提交 urlencoded编码  

除了method为post其他和get相同

post提交 form-data编码 #包含文件  

form表单提交
<div class="container-fluid">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h1 class="text-center">登录界面</h1>
            <form action="" method="post" enctype="multipart/form-data">  #注意修改编码
                {% csrf_token %}
                <div class="form-group">
                    <label for="id_username">用户名:</label>
                    <input type="text" class="form-control" id="id_username" placeholder="用户名"
                           aria-describedby="basic-addon1" name="username">
                </div>
                <div class="form-group">

                    <label for="id_password">密码:</label>
                    <input type="password" class="form-control" id="id_password" placeholder="密码"
                           aria-describedby="basic-addon1" name="password">
                </div>
                <div class="form-group">
                    <label for="id_file">上传文件:</label>
                    <input type="file" id="id_file" aria-describedby="basic-addon1" name="file">
                </div>

                <div class="form-group">
                    <input class="btn btn-danger" type="submit">
                </div>
            </form>

        </div>

    </div>
</div>

========================================================================
ajax提交
<div class="container-fluid">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h1 class="text-center">登录界面</h1>
            <form action="" method="post" enctype="multipart/form-data">
                {% csrf_token %}
                <div class="form-group">
                    <label for="id_username">用户名:</label>
                    <input type="text" class="form-control" id="id_username" placeholder="用户名"
                           aria-describedby="basic-addon1" name="username">
                </div>
                <div class="form-group">

                    <label for="id_password">密码:</label>
                    <input type="password" class="form-control" id="id_password" placeholder="密码"
                           aria-describedby="basic-addon1" name="password">
                </div>
                <div class="form-group">
                    <label for="id_file">上传文件:</label>
                    <input type="file" id="id_file" aria-describedby="basic-addon1" name="file">
                </div>

                <div class="form-group">
                    <input class="btn btn-danger" type="submit">
                </div>
            </form>

        </div>

    </div>
</div>


<div>
	<div class="form-group">
		<label for="id_username">用户名:</label>
		<input type="text" class="form-control" id="id_username" placeholder="用户名"
			   aria-describedby="basic-addon1" name="username">
	</div>

	<div class="form-group">
		<label for="id_password">密码:</label>
		<input type="password" class="form-control" id="id_password" placeholder="密码"
			   aria-describedby="basic-addon1" name="password">
	</div>

	<div class="form-group">
		<label for="id_file">上传文件:</label>
		<input type="file" id="id_file" aria-describedby="basic-addon1" name="file">
	</div>

	<div class="form-group">
		<input class="btn btn-danger" type="button" value="提交" id="data_submit">
	</div>


	<script>
		$('#data_submit').click(function () {
			var formdata = new FormData();
			formdata.append('myfile', $("#id_file")[0].files[0]);
			formdata.append('csrfmiddlewaretoken', '{{ csrf_token }}');
			formdata.append('name', $("#id_username").val());
			formdata.append('password', $("#id_password").val());
			$.ajax({
				url: {% url 'login' %},
				method: 'post',
				processData: false,
				contentType: false,
				data: formdata,
				success: function (response) {
					console.log(response)

				}
			})
		})
</div>

post提交 json编码 使用ajax  

<div class="form-group">
    <label for="id_username">用户名:</label>
    <input type="text" class="form-control" id="id_username" placeholder="用户名"
           aria-describedby="basic-addon1" name="username">
</div>

<div class="form-group">
    <label for="id_password">密码:</label>
    <input type="password" class="form-control" id="id_password" placeholder="密码"
           aria-describedby="basic-addon1" name="password">
</div>

<div class="form-group">
    <input class="btn btn-danger" type="button" value="提交" id="data_submit">
</div>

        <script>
                    $('#data_submit').click(function () {
                $.ajax({
                    url: {% url 'login' %},
                    method: 'post',
                    contentType: 'application/json',
                    headers:{'X-CSRFToken':'{{csrf_token}}'},
                    data:JSON.stringify({name:$("#id_username").val(),password:$("#id_password").val()}),

                    success: function (response) {
                        console.log(response)
                    }
                })

             });

        </script>

中间件代码

class Data_Conv(MiddlewareMixin):

    def process_request(self, request):
        request.data = {}
        # get提交数据,urlencoded编码方式,把form数据转换成一个字串(name1=value1&name2=value2…)
        if request.method == 'GET' and request.META.get('CONTENT_TYPE') == 'application/x-www-form-urlencoded':
            for k in request.GET:
               request.data[k]=request.GET[k]

        # post提交数据,urlencoded编码方式,把form数据封装到http body中
        elif request.method == 'POST' and request.META.get('CONTENT_TYPE') == 'application/x-www-form-urlencoded':
            for k in request.POST:
                request.data[k] = request.POST[k]

        # post提交数据,form-data编码方式,把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),
        # Content-Type(默认为text/plain),name(控件name)等信息,并加上分割符(boundary).
        # 需要注意的是POST中只有文件的名称,文件的数据实际保存在request.FILES中,通过  request.FILES.get('myfile').chunks()获取文件的数据
        elif request.method == 'POST' and request.META.get('CONTENT_TYPE') == 'multipart/form-data':
            for k in request.POST:
                request.data[k] = request.POST[k]

        # post提交数据,json编码方式, ajax请求中 content-type:application/json,在后台接受前台提交的数据,前端提交的数据是 json格式的字符串
        elif request.method == 'POST' and request.META.get('CONTENT_TYPE') == 'application/json':
            post_data = json.loads(request.body)
            for k in post_data:
                request.data[k] = post_data[k]

实现频率限制的功能(同一个ip地址,一分钟只能访问5次)

class OverTime(MiddlewareMixin):
    def process_request(self, request):
        # 获取客户端IP地址
        IP = request.META.get('REMOTE_ADDR')
        print(IP)
        # 获取该IP地址的值,如果没有,给一个默认列表[]
        lis = request.session.get(IP, [])
        # 获取当前时间
        curr_time = time.time()
        # 判断操作次数是否小于3次
        if len(lis) < 3:
            # 如果小于3次,添加本次操作时间
            lis.append(curr_time)
            # 保存
            request.session[IP] = lis
        else:
            # 如果本次操作时间减去第一次操作时间小于60秒,则不让其继续操作
            if time.time() - lis[0] < 60:
                return HttpResponse('操作过于频繁')
            else:
                # 如果大于60秒则交叉复制
                lis[0], lis[1], lis[2] = lis[1], lis[2], time.time()
                # 保存
                request.session[IP] = lis

  

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/282575.html

(0)
上一篇 2022年8月28日
下一篇 2022年8月28日

相关推荐

发表回复

登录后才能评论