Django杂篇(2)

Django杂篇(2)

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

cookie与session

首先咱们要知道,HTTP协议自己是无状态的,无状态的概念是什么?python

无状态的意思就是当用户的请求经过HTTP发给后端的时候,HTTP自己是不保留用户的任何状态的,即每次用户发送HTTP都会当作是用户第一次发送数据,这是很是不合理的,试想一下,若是咱们登录一个购物网站,登录成功以后想要作购买商品,但是是作不了的,由于HTTP无状态,每次登录都是第一次登录,咱们老是在不停地登录,就没办法作任何操做.ajax

因此就引出了cookie和session的概念,他们都是用来让用户"保持状态"的,便可以让用户处于登录状态下,从而进行一系列的操做.数据库

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

查看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')
相关文章
相关标签/搜索