• python框架之Django(9)-CSRF


    准备

    现有如下模板和视图:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>登录</title>
     6 </head>
     7 <body>
     8 <form action="/login/" method="post">
     9     <p>用户名:<input type="text" name="username"></p>
    10     <p>密码:<input type="text" name="password"></p>
    11     <p><input type="submit" value="提交"></p>
    12     <p style="color: red"> {{ msg }}</p>
    13 </form>
    14 </body>
    15 </html>
    login.html
     1 from django.shortcuts import render,HttpResponse
     2 
     3 
     4 def login(request):
     5     if request.method == 'POST':
     6         username = request.POST.get('username')
     7         password = request.POST.get('password')
     8         print(username, password)
     9         return HttpResponse('登陆成功')
    10     else:
    11         return render(request, 'login.html')
    views.py

    使用

    表单提交

    使用上述模板中表单直接进行提交时,会发现会返回403错误如下:

    这是因为Django中默认配置了一个拦截CSRF请求的中间件,在settings.py中可配置:

    1 MIDDLEWARE = [
    2     'django.middleware.security.SecurityMiddleware',
    3     'django.contrib.sessions.middleware.SessionMiddleware',
    4     'django.middleware.common.CommonMiddleware',
    5     'django.middleware.csrf.CsrfViewMiddleware',  # 此项便是拦截CSRF请求的中间件
    6     'django.contrib.auth.middleware.AuthenticationMiddleware',
    7     'django.contrib.messages.middleware.MessageMiddleware',
    8     'django.middleware.clickjacking.XFrameOptionsMiddleware',
    9 ]
    settings.py
    • 方案一:去除该中间件(不推荐)

      直接注释该行即可。

      1 MIDDLEWARE = [
      2     'django.middleware.security.SecurityMiddleware',
      3     'django.contrib.sessions.middleware.SessionMiddleware',
      4     'django.middleware.common.CommonMiddleware',
      5     # 'django.middleware.csrf.CsrfViewMiddleware',  # 此项便是拦截CSRF请求的中间件
      6     'django.contrib.auth.middleware.AuthenticationMiddleware',
      7     'django.contrib.messages.middleware.MessageMiddleware',
      8     'django.middleware.clickjacking.XFrameOptionsMiddleware',
      9 ]
      setting.py

      注释之后就可以正常提交请求了。

    • 方案二:表单中添加csrf_token

       1 <!DOCTYPE html>
       2 <html lang="en">
       3 <head>
       4     <meta charset="UTF-8">
       5     <title>登录</title>
       6 </head>
       7 <body>
       8 <form action="/login/" method="post">
       9     {% csrf_token %}
      10     <p>用户名:<input type="text" name="username"></p>
      11     <p>密码:<input type="text" name="password"></p>
      12     <p><input type="submit" value="提交"></p>
      13     <p style="color: red"> {{ msg }}</p>
      14 </form>
      15 </body>
      16 </html>
      login.html

      在表单中添加上‘{%csrf_token%}’之后,查看网页源代码会发现表单中多了一个隐藏的输入框,如下:

      Django通过这种方式让表单的请求带着token一起发送到服务器去验证。

    Ajax请求

    修改login.html内容如下:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>登录</title>
     6     <script src="/static/jquery.min.js"></script>
     7 </head>
     8 <body>
     9 <script>
    10     function login() {
    11         $.ajax({
    12             url: "/login/",
    13             type: "POST",
    14             data: {"usr": "admin", "pwd": "123"},
    15             {#headers:{ "X-CSRFtoken":$.cookie("csrftoken")},#}
    16             success: function (data) {
    17                 alert(data)
    18             }
    19         })
    20     }
    21     login()
    22 </script>
    23 </body>
    24 </html>
    login.html

    访问该页面会发现与表单请求一样被拦截:

    • 方案一:headers中携带csrf_token

       1 <!DOCTYPE html>
       2 <html lang="en">
       3 <head>
       4     <meta charset="UTF-8">
       5     <title>登录</title>
       6     <script src="/static/jquery.min.js"></script>
       7 </head>
       8 <body>
       9 <script>
      10     function login() {
      11         $.ajax({
      12             url: "/login/",
      13             type: "POST",
      14             data: {"usr": "admin", "pwd": "123"},
      15             headers: {
      16                 "X-CSRFtoken": '{{csrf_token}}'
      17             },
      18             success: function (data) {
      19                 alert(data)
      20             }
      21         })
      22     }
      23     login()
      24 </script>
      25 </body>
      26 </html>
      login.html
    • 方案二:data中携带csrf_token

       1 <!DOCTYPE html>
       2 <html lang="en">
       3 <head>
       4     <meta charset="UTF-8">
       5     <title>登录</title>
       6     <script src="/static/jquery.min.js"></script>
       7 </head>
       8 <body>
       9 {% csrf_token %}
      10 <script>
      11     function login() {
      12         $.ajax({
      13             url: "/login/",
      14             type: "POST",
      15             data: {"usr": "admin", "pwd": "123", "csrfmiddlewaretoken": '{{csrf_token}}'},
      16             success: function (data) {
      17                 alert(data)
      18             }
      19         })
      20     }
      21 
      22     login()
      23 </script>
      24 </body>
      25 </html>
      login.html

    补充

    全局添加csrf_token

    如果页面中有多个ajax请求的话就可以通过下面方式在所有的ajax中添加headers信息:

    $.ajaxSetup({
            beforeSend: function (xhr, settings) {
                xhr.setRequestHeader("X-CSRFtoken", '{{csrf_token}}')
            }
        });

    这样就会在提交ajax之前执行这个方法,从而在所有的ajax里都加上这个csrftoken。

    仅post提交添加csrf_token

    如果想要实现在当get方式的时候不需要提交csrftoken,当post的时候需要,实现这种效果的代码如下:

    function csrfSafeMethod(method) {
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    
    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", '{{ csrf_token }}');
            }
        }
    });

    上述示例因csrf_token都是通过模板语言取出,所以html页必须由django的render函数渲染过。同理也可通过js取出cookie中csrf_token值,填充到对应位置即可。

    指定视图函数不校验csrf

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def view_func(request):
        pass
  • 相关阅读:
    delphi 类型转化
    VCL主要框架
    delphi TFileStream.create
    delphi常用函数过程
    VMT & DMT
    index.jsp报错The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path的解决办法
    the selection cannot be run on any server错误解决方法
    从request获取各种路径总结
    A Java Exception has occurred 和 org/apache/juli/logging/LogFactory错误解决方法
    操作系统第5次实验报告:内存管理
  • 原文地址:https://www.cnblogs.com/zze46/p/9774076.html
Copyright © 2020-2023  润新知