中间件、跨站请求伪造csrf、auth模块

一、中间件

中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。

说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

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',
]
settings.py

MIDDLEWARE配置项是一个列表(列表是有序的)列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。

 

 

自定义中间件

中间件可以定义五个方法,分别是:(主要的是process_request和process_response)

  • process_request(self,request)
  • process_view(self, request, view_func, view_args, view_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)
  • process_response(self, request, response)

以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。

process_request

process_request有一个参数,就是request,这个request和视图函数中的request是一样的(在交给Django后面的路由之前,对这个request对象可以进行一系列的操作)。

由于request对象是一样的,所以我们可以对request对象进行一系列的操作,包括request.变量名=变量值,这样的操作,我们可以在后续的视图函数中通过相同的方式即可获取到我们在中间件中设置的值。

它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。

总结一下:

  1. 中间件的process_request方法是在执行视图函数之前执行的。
  2. 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
  3. 不同中间件之间传递的request都是同一个对象

process_response
响应走的时候会按照配置文件中注册的中间件从下往上的顺序依次执行每一个中间件里面的
process_response方法 该方法必须要有两个形参 并且需要将形参response返回
如果你内部自己返回了HttpResponse对象 会将返回给用户浏览器的内容替换成你自己的

process_view

process_view(self, request, view_func, view_args, view_kwargs)

该方法有四个参数

request是HttpRequest对象。

view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)

view_args是将传递给视图的位置参数的列表.

view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。

Django会在调用视图函数之前调用process_view方法。

它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,那么将不会执行Django的视图函数,而是直接在中间件中掉头,倒叙执行一个个process_response方法,最后返回给浏览器

process_view方法是在Django路由系统之后,视图系统之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的

process_exception

process_exception(self, request, exception)

该方法两个参数:

一个HttpRequest对象

一个exception是视图函数异常产生的Exception对象。

这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。

process_template_response(用的比较少)

process_template_response(self, request, response)

它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。

process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。

中间件的执行流程

如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。

 

 

 二、跨站请求伪造csrf

钓鱼网站:本质就是搭建一个跟正常网站一模一样的页面,用户在该页面上完成转账功能,在给用户书写的form表单中,对方账户的input中没有name属性,自己偷偷地提前写好一个默认隐藏的具有name属性的input框

form表单如何通过csrf校验

只需要在你的form表单内写一个
{% csrf_token %}

ajax如何通过csrf校验

// 第一种方式 自己手动获取
 {#data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},#}
// 第二种方式 利用模板语法
{#data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
// 第三种     通用方式 引入外部js文件  官网提供的方式
{% load static %}
<script src="{% static 'myset.js' %}"></script>
data:{'username':'jason'}
 第三种  通用方式 引入外部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);
    }
  }
});
myset.js

csrf相关装饰器

当我们网站整体都校验csrf的时候 我想让某几个视图函数不校验

当我们网站整体都不校验csrf的时候 我想让某几个视图函数校验

from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.views import View9
from django.utils.decorators import method_decorator

# @method_decorator(csrf_protect,name='post')  # 第二种指名道姓的给类中某个方法装
# @method_decorator(csrf_exempt,name='post')  # csrf_exempt 第二种方式不行
@method_decorator(csrf_exempt,name='dispatch')  # 可以!!!
class MyHome(View):  # APIView
    # @method_decorator(csrf_protect)  # 第三种 类中所有的方法都装
    # @method_decorator(csrf_exempt)  # csrf_exempt 第三种方式可以
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)

    def get(self,request):
        return HttpResponse('get')
    # @method_decorator(csrf_protect)  # 第一种方式
    # @method_decorator(csrf_exempt)  # csrf_exempt 第一种方式不行
    def post(self,request):
        return HttpResponse('post')

给CBV加装饰器 推荐你使用模块method_decorator

csrf_exempt是一个特例 只能给dispatch方法装

三、auth模块

Auth模块是Django自带的用户认证模块:

我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能

模块导入

from django.contrib import auth
from django.contrib.auth.models import User

auth方法大全

1.创建用户

User.objects.create()  # 密码是明文
User.objects.createuser()  # 基本都用它 
User.objects.createsuperuser()  # 邮箱要给数据

2.校验用户名和密码是否正确(认证功能)

user_obj = auth.authenticate(username=username,password=password) # 用户名和密码两个都不能少 # 该方法当用户名和密码正确的时候返回的用户对象 不正确返回None

3.保存用户登录状态

auth.login(request,user_obj)  # 这一句执行之后 request.user获取当前登录的用户对象

4.如何判断当前用户是否登录 以及如何获取当前登录用户对象

request.user.is_authenticated()  # 判断是否登录
request.user  # 登录用户对象

5.校验用户是否登录

from django.contrib.auth.decorators import login_required
# 局部配置
@login_required(login_url='/login/')
def xxx(request):
    return HttpResponse('xxx页面')

# 全局配置
配置文件中写以下代码
LOGIN_URL = '/login/'
@login_required
def xxx(request):
    return HttpResponse('xxx页面')

# 如果两个都设置了 那么优先执行局部配置

6.修改密码

request.user.check_password(old_password)  # 校验原密码是否正确

request.user.set_password(new_password)
request.user.save()                        # 一定要保存 

7.注销功能

auth.logout(request)

如何扩展auth_user表

1.利用一对一表关系()

2.利用类的继承

# 1 类的继承
from django.contrib.auth.models import User,AbstractUser
# Create your models here.
class Userinfo(AbstractUser):
    phone = models.BigIntegerField()
    avatar = models.FileField()
    # 扩展的字段 尽量不要与原先表中的字段冲突

# 2 配置文件 要在settings.py中告诉Django,我现在使用我新定义的UserInfo表来做用户认证
AUTH_USER_MODEL = '应用名.表名'
AUTH_USER_MODEL = "app名.UserInfo"

""" django就会将userinfo表来替换auth_user表 并且之前auth模块所有的功能不变 参照的也是userinfo表 """

 

 

end

posted @ 2020-01-14 19:25  小猪皮蛋  阅读(135)  评论(0编辑  收藏  举报