Django入门到放弃之CSRF_TOKEN

1.django解决csrf攻击方法

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

form表单使用:

1
-在form表单中 {% csrf_token%}

ajax提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
方式一:放到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

1
2
3
4
5
6
7
8
9
10
11
# 全局启用,局部禁用(中间件不能注释,这个视图函数,已经没有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

1
2
3
4
5
6
7
8
9
10
@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中

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

5.代码示例

登录认证中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# (没有登录就可以访问: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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
无论前端是什么编码的请求,后端视图函数都有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编码  

1
除了method为post其他和get相同

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<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>

中间件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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次)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

  

posted @   百衲本  阅读(332)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
历史上的今天:
2020-08-27 Linux 五种IO模型
cnblogs_post_body { color: black; font: 0.875em/1.5em "微软雅黑" , "PTSans" , "Arial" ,sans-serif; font-size: 15px; } cnblogs_post_body h1 { text-align:center; background: #333366; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 23px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } cnblogs_post_body h2 { text-align:center; background: #006699; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 20px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } cnblogs_post_body h3 { background: #2B6695; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 18px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } 回到顶部 博客侧边栏 回到顶部 页首代码 回到顶部 页脚代码
点击右上角即可分享
微信分享提示