zoukankan      html  css  js  c++  java
  • Django杂篇(2)

    Django杂篇(2)

    本文主要介绍cookie与session组件,django中间件以及CSRF的一些介绍.

    cookie与session

    首先我们要知道,HTTP协议本身是无状态的,无状态的概念是什么?

    无状态的意思就是当用户的请求通过HTTP发给后端的时候,HTTP本身是不保留用户的任何状态的,即每次用户发送HTTP都会当做是用户第一次发送数据,这是非常不合理的,试想一下,如果我们登陆一个购物网站,登陆成功之后想要做购买商品,可是是做不了的,因为HTTP无状态,每次登陆都是第一次登陆,我们总是在不停地登陆,就没办法做任何操作.

    所以就引出了cookie和session的概念,他们都是用来让用户"保持状态"的,即可以让用户处于登陆状态下,从而进行一系列的操作.

    cookie的实际本体只是一段字符串,他是从服务器发送出来并且存放在浏览器(客户端)上的一组组键值对,当浏览器下次访问服务端的时候,就会在request请求里面自动携带这个字符串,服务端就可以识别这个字符串,根据这个cookie来解析出你的身份,哦,原来我们之前见过,而且进行过一些互动~

    查看cookie也非常简单,我们只需要在任何浏览器里面,按F12->找到Network标签->找到下面的二级标签Cookies即可,里面就是当前网页的cookie信息.

    那么我们在django里面怎么对cookie做操作呢,实例如下:

    # 获取cookie
    request.COOKIES.get('key')#因为cookie其实是一个字典,所以用get取值比较好,取值时候尽量不要用中括号取值,因为中括号取值如果取不到会报错,影响整个项目的运行
    
    
    # 设置cookie
    # 要先取到一个对象,可以是HttpResponse(),也可以是render()或者redirect()
    obj = HttpResponse()
    obj.set_cookie(key,value...)
    
    
    # 删除cookie
    # 同样需要先取到一个对象,然后对其做操作
    obj = HttpResponse()
    obj.delete_cookies("key")
    

    session

    既然我们已经有了cookie这个可以保持用户状态的工具,为什么还要引入session的概念呢?大致原因有以下两条:

    1. cookie本身支持的长度较小,最大只支持4096字节,不足以支持非常大的项目以及用户量
    2. cookie本身存在浏览器(客户端),我们知道存在于浏览器的数据是公开的,并不安全,使用者可以随时更改或者拦截这些数据,从而拿着这些cookie来做非法的事情,不太安全

    所以,为了解决以上两个问题,我们引入了session的概念,一方面session可以支持更大的数据,另一方面session是存放于服务端的,安全性比存放于浏览器的cookie要高得多.

    话虽如此,但其实session并不是取代cookie而存在的东西,而是共存的事物,因为cookie解决的是HTTP协议的无状态的问题,让服务端知道来的用户是谁,然后我们通过cookie识别不同的用户,进而在服务端的session里面保存该用户私密的信息,以及那些长度超过cookie限制的文本数据.

    另外要注意一点的是,在django里面的session的产生是针对同一台机器的不同浏览器而言的,即我们使用同一台机器的同一个浏览器在后端的数据库表里永远只会有一条session记录,新生成的会把旧的覆盖掉,只有我们更换浏览器或者更换机器才会生成两条不同的session记录.

    下面介绍我们怎么样在django里面对session操作

    # 获取session
    request.session.get('key',None)
    # 一样用get取值,如果值不存在就返回None
    request.session.session_key
    # 可以获取该会话session的key值
    
    # 设置session值
    request.session['key']=value
    request.session.setdefault('key',value)
    # 可以直接用key,value的方式进行赋值,setdefault的优势在于如果设置的值已经存在则不会改变原值,如果不存在就会添加值
    request.session.set_expiry(value=)
    '''可以配置session的有效时间,里面的参数value有多种写法
    1. 如果写的是数字,就是按秒计算有效时间,数字即为秒数
    2. 如果为0,则session在关闭浏览器后就会失效,即只会生效在当前打开的浏览器中
    3. 如果为空白,就会使用django默认的时间,即14天的有效时间
    4. 如果为是一个datetime或者timedelta时间,则会在这个时间后失效
    '''
    
    # 删除session值
    del request.session['key']
    request.session.delete()	#只会删除服务端的session
    request.session.flush()		#会同时删除服务端的session和客户端的cookie
    

    使用session还有一个好处:客户端只有cookie的值,并不能直接看到用户的信息,而后端的session是依赖于cookie的,所以这里就形成了一个前后端分离的状态,cookie保存在客户端,session保存在服务端,极大提升了数据的安全性.

    django中间件

    首先,我们要了解什么是中间件?

    就名字来看,中间件就是中间的一个组件,我们可以把我们整个后端看成一个学校,那么中间件就是学校的门卫室,不管用户的请求进入后端或者是从后端出来,都要经过中间件的检查,检查不通过就无法继续交互.

    上面是按照生活中的看法来说的,就官方的说法来说,中间件就是一个钩子,一个用来处理Django的请求和响应的钩子,可以用来控制全局范围内Django的输入和输出,常用的中间件有七个,每个中间件都会负责一些特定的功能,且这些功能大多生效在视图函数的执行之前或者执行之后,中间件的本质还是一个类,以类中定义方法的形式来限制Django的输入和输出的格式.

    其实我们之前已经接触过中间件,只不过当时我们都是把其中的一条注释掉,因为不注释的话会影响我们程序的正常运行,自今天起我们就不用做注释掉这么low的操作了,我们可以光明正大的去使用并且可以尝试自己写中间件了.

    首先我们要知道中间件在哪里,在settings.py文件里,如下:

    # settings.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',
    ]
    # 首先,该配置项是一个列表,请求在经过中间件的时候是从上到下进入这些方法进行判断的
    # 以上就是系统默认的七个中间件,当然我们可以手动写一个属于自己的中间件,当然,在自己写中间件之前,我们要先了解一下这些中间件都包含有什么方法,以及是怎么运作的
    

    自定义中间件

    我们先来看如何自定义中间件:

    1. 首先我们需要新建一个文件夹(这里我们命名为mymiddleware),任意名字都可以,然后里面建一个任意名字的py文件(这里我们命名为myaabb.py),里面写一个类,有固定的继承的父类

      #/app01/mymiddleware/myaabb/
      from django.utils.deprecation import MiddlewareMixin
      class MyMiddle(MiddlewareMixin):
              ...
      
    2. 建立好类之后,我们还需要去settings.py文件里面注册,注册非常简单,就是把我们创建这个文件夹和文件的路径写入MIDDLEWARE的列表里就可以了.

      # settings.py
      MIDDLEWARE = [
           'app01.mymiddleware.myaabb.MyMiddlel',
      ]
      

    下面我们就可以在我们自定义的文件中定义类和写我们需要的方法了,其实中间件里面常用的自定义方法只有五个,每个中间件里所定义的方法也都在这五个方法之内,如下:

    '''
    1.process_request:该方法是请求来的时候自动触发,要注意点,在该方法内如果有return HTTPResponse(),那么之后的中间件都不会再执行,会执行同一级别的process_response,然后从该中间件直接返回,实例如下
    '''
    def process_request(self,request):
        print('我是自定义中间件里面的process_request方法')
       	return HttpResponse("我是自定义中间件里面的HttpResponse对象返回值")  # 直接原地返回
        
    '''
    2.process_response:该方法是响应走的时候调用的,即请求在经过了中间件,urls,views之后,返回值再次走到中间件的时候会调用process_response,且调用顺序是从下到上,即MIDDLEWARE里面从下到上的调用每个中间件的process_response
    '''
    def process_response(self,request,response):  # response就是要返回给用户的数据
    	print("我是第一个自定义中间件里面的process_response方法")
    	return response		# 这里要注意,凡是形参里面带有response的,最后一定要return response,否则返回值数据会丢失
    
    '''
    3. process_view:会在路由(urls.py)匹配成功之后执行视图函数(views.py)之前触发
    4. process_exception:当视图函数(views.py)出现bug的时候自动触发
    5. process_template_response:当视图函数执行完毕之后并且返回的对象中含有render方法的情况下才会触发(最不常用)
    '''
    

    跨站请求伪造(csrf)

    跨站请求伪造,全称(Cross-site request forgery),可能我们会对这个名字比较陌生,但是换个叫法我们就熟悉了,钓鱼网站.简单来说就是欺骗用户的浏览器,让其以用户的名义运行操作,达到制作钓鱼网站的人的目的.

    CSRF的解决方案

    CSRF最常用的解决方案即是添加一个校验用token,改数据不保存在cookie中,且攻击者很难伪造,token其本质就是一串随机数,是由服务端生成并发给客户端的,在客户端提交数据的时候会随着数据一起提交,供服务端来校验,校验通过才会接收客户端的请求并做处理,若token错误或为空,服务端就会拒绝这个请求

    添加校验token

    FORM表单添加

    form表单添加token非常简单,在form表单的内部直接加上{% csrf_token %}即可,在任何位置都可以.

    AJAX添加

    AJAX添加token的方法常用的有三种

    # 1. 通过标签查找并添加
    data:{'username':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()}
        
    # 2. 通过django的模板语法来添加,这种方法用处有限,因为如果前后端分离的话,后端可能不会用django来搭建,所以模板语法也就不能使用了.
    data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
        
    # 3. 拷贝一个js文件,然后导入到前端的html文件里即可,这里我们新建static文件夹,并在里面新建一个setup.js文件然后粘贴以下代码
    # /static/setup.js
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');
    
    
    
    function csrfSafeMethod(method) {
      // these HTTP methods do not require CSRF protection
      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    
    $.ajaxSetup({
      beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
    
    
    # 完成之后我们还需要配置两个地方,一个就是settings.py,一个就是我们的html文件里,AJAX的上方
    # settings.py
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR,'static')
    ]
    
    # **.html,直接导入该js文件即可
    <script src="/static/setup.js"></script>
    

    装饰器方式

    装饰器方式主要是用于CBV上,且使用时候要注意

    1. csrf_exempt只能用于CBV里面的dispatch方法上面,不能用于别的方法
    2. 除了csrf_exempt之外,其他所有的装饰器都可以加在不同的方法上,比如get或者post

    比如:

    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
    # csrf_exempt  只能用于装饰dispatch
    # 第一种
    # @method_decorator(csrf_exempt,name='dispatch')
    class MyCsrf(View):
        # 第二种
        @method_decorator(csrf_exempt)
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request,*args,**kwargs)
        def get(self,request):
            return HttpResponse('hahaha')
    
    # 除了csrf_exempt之外 所有的其他装饰器 在CBV上面都有三种方式,即在类外部,或者类内部的方法上方
    @method_decorator(csrf_protect,name='post')
    class MyCsrf(View):
        @method_decorator(csrf_protect)
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request,*args,**kwargs)
        def get(self,request):
            return HttpResponse('hahaha')
        @method_decorator(csrf_protect)
        def post(self,request):
            return HttpResponse('post')
    
  • 相关阅读:
    1.4 build命令
    2.2-2 文章模块开发【添加文章页面脚本编写】
    2.2-1 文章模块开发 【入口脚本及模板的创建】
    2.1 开始一个项目 【功能梳理】
    [微信小程序]不在以下合法域名列表中
    [微信小程序]swiper保持宽高比
    爸爸一路走好
    LVM日记
    欲玩Discuz_X3.2,无奈不支持php7,再装个php5.3,编译到一半报错
    /sbin/ldconfig: /usr/local/lib64/libstdc++.so.6.0.22-gdb.py 不是 ELF 文件
  • 原文地址:https://www.cnblogs.com/Xu-PR/p/11767279.html
Copyright © 2011-2022 走看看