Django入门到放弃之CSRF_TOKEN
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}}'},
# 全局启用,局部禁用(中间件不能注释,这个视图函数,已经没有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('登录成功')
@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('登录成功')
path('csrf_test/', csrf_exempt(views.csrf_test))
# (没有登录就可以访问: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
前端代码:
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]
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
"一劳永逸" 的话,有是有的,而 "一劳永逸" 的事却极少