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

Django的中间件

中间件可以实现控制全局的效果

中间件的介绍

官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变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',]

中间件就类似于Django的保安

请求的时候需要经过中间件才能到达Django后端(urls,views,templates,models)

响应走的时候也需要经过中间件才能到达web服务网关接口

django中间件中有五个用户可以自定义的方法

# 需要掌握的方法
process_required
process_response()

# 需要了解的方法
process_view()
process_exception()
process_template_response()

img

上面是完整的Django的生命周期

我们可以自定义Django中间件

img

自定义中间件,需要在根目录下建立一个文件夹,随笔命名一个py文件,在py文件中写自定义中间价

但必须继承

from django.utils.deprecation import MiddlewareMixin

img

接下来我们一一分析五个提供给用户自定义的方法

1 process_request()

    def process_request(self, request):  # 需要接收request参数
        print('我是第一个自定义的中间件的process_request方法')

process_request()方法会在web请求来时执行,会在urls.py之前执行

而且执行顺序从上而下执行

img

2 process_response()

当视图函数返回HttpResponse时执行

class MyMiddle(MiddlewareMixin):
    def process_response(self, request, response):  # 需要接收response参数
        print('我是第一个自定义中间件的process_response方法')
        return response  # 一定要将response返回

执行顺序从下往上执行

img

注意

​ 在Django中

​ 当process_request方法中返回HttpResponse对象时,并不会再往下执行,并不会执行urls.pyheviews.py连接下来的中间件也不会执行了,而是直接走同级别的process_response方法

img

​ 在Flask中

​ 当process_request方法中返回HttpResponse对象时,会直接绕开剩下来的中间件,直接到最后一个中间件,从下往上执行process_response方法

img

了解知识点

process_view

在路由匹配成功执行视图函数之前 触发

这个方法夹在路由层与视图层中间, 执行顺序从上往下

  def process_view(self,request,view_func,view_args,view_kwargs):
        print(view_func)
        print(view_args)
        print(view_kwargs)
        print('我是第一个中间件里面的process_view方法')
process_exception

当你的视图函数报错时 就会自动执行, 执行顺序从下向上

    def process_exception(self, request, exception):
        print('我是第一个中间件里面的process_exception')
process_template_response

当你返回的HttpResponse对象中必须包含render属性才会触发

def index(request):
    print('我是index视图函数')
    def render():
        return HttpResponse('什么鬼玩意')
    obj = HttpResponse('index')
    obj.render = render
    return obj
    def process_template_response(self, request, response):
        print('我是第一个中间件里面的process_template_response')
        return response

总结:

你在书写中间件的时候 只要形参中有repsonse 你就顺手将其返回 这个reponse就是要给前端的消息

而且中间件方法执行的顺序,前端数据传来时,走的方法执行顺序都是从上往下

​ 当后端要将数据返回时,走的中间件方法都是从下往上

csrf跨站请求伪造

钓鱼网站
通过制作一个跟正儿八经的网站一模一样的页面,骗取用户输入信息 转账交易
从而做手脚
转账交易的请求确确实实是发给了中国银行,账户的钱也是确确实实少了
唯一不一样的地方在于收款人账户不对
内部原理
在让用户输入对方账户的那个input上面做手脚
给这个input不设置name属性,在内部隐藏一个实现写好的name和value属性的input框
这个value的值 就是钓鱼网站受益人账号
防止钓鱼网站的思路
网站会给返回给用户的form表单页面 偷偷塞一个随机字符串
请求到来的时候 会先比对随机字符串是否一致 如果不一致 直接拒绝(403)

该随机字符串有以下特点
1.同一个浏览器每一次访问都不一样
2.不同浏览器绝对不会重复

1.form表单发送post请求的时候 需要你做得仅仅书写一句话
{% csrf_token %}

{%csrf_token%}在前端的显示就是一个input框

<input type="hidden" name="csrfmiddlewaretoken" value="2LrnVLNcRGkYbhzDxc3cXNQnLFb8NqZBgOrKo3RnijNKH4Xy7LovCfNtPHUXwkKN">

2.Ajax发送post请求时如何避免

第一种方式

 $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data: {'csrfmiddlewaretoken': $('[name=csrfmiddlewaretoken]').val(),  // 通过属性选择器拿到csrf_token  input标签
                    'name': '鸡哥几把的鸡'},
            success:function (data) {
                alert(data)
            }

        })
    })

第二种方式

    $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data: {'csrfmiddlewaretoken': '{{ csrf_token }}',  // 直接写{{ csrf_token }} 但是必须加引号
                    'name': '鸡哥几把的鸡'},
            success:function (data) {
                alert(data)
            }

        })
    })
注意

​ 第一种方式和第二种方式的cerf_token的键 固定就是 "csrfmiddlewaretoken"

第三张方式

直接导入外部的js文件

注意

​ 外部js文件我们都要将其放在static文件夹中

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);
					}
				  }
				});

导入js文件

{% load static %}
<script src="{% static 'myjs/cs.js' %}">
    $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data: {'name': '鸡哥几把的鸡'},  // 不用再在data中写入csrf_token
            success:function (data) {
                alert(data)
            }

        })
    })

</script>

1.当你网站全局都需要校验csrf的时候 有几个不需要校验该如何处理
2.当你网站全局不校验csrf的时候 有几个需要校验又该如何处理

首先先给FVB加装饰器

from django.views.decorators.csrf import csrf_exempt, csrf_protect

from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_protect  # 在全局都不需要csrf_token校验时,这个装饰器装饰的函数,post请求需要校验
def login(request):
    return HttpResponse('login')

@csrf_exempt  # 在全局都需要csrf_token校验时,这个装饰器装饰的函数,post请求可以不需要校验
def register(request):
    return HttpResponse('register')

给CBV加装饰器

分两种情况进行讨论

第一种 在全局都不需要csrf_token校验时

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


# @method_decorator(csrf_protect, name='post')  # 第一种方式
class MyView(views.View):

    @method_decorator(csrf_protect)  # 第三张方式
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def get(self, request):
        return HttpResponse('get')

    # @method_decorator(csrf_protect)  # 第二种方式
    def post(self, request):
        return HttpResponse('post')

第二种 在全局都需要csrf_token校验时

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

# @method_decorator(csrf_exempt, name='dispatch')  # 第二种
class MyView(views.View):

    @method_decorator(csrf_exempt)  # 第一种
    def dispatch(self, request, *args, **kwargs):
        res = super().dispatch(request, *args, **kwargs)
        return res

    def get(self, request):
        return HttpResponse('get')


    def post(self, request):
        return HttpResponse('post')

之前我们给登录做校验session的装饰器,只给FBV做了,现在学了method_decorator之后也可以给CBV做登录认证装饰器

总结

​ 装饰器中只有csrf_exempt是特例,其他的装饰器在给CBV装饰的时候 都可以有三种方式

Auth模块

Auth模块是什么

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

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

Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。

auth模块的功能

# 查询用户
from django.contrib import auth
user_obj = auth.authenticate(username=username,password=password)  # 必须要用 因为数据库中的密码字段是密文的 而你获取的用户输入的是明文  authenticate中起码要写入两个参数

# 记录用户状态
auth.login(request,user_obj)  # 将用户状态记录到session中

# 判断用户是否登录
print(request.user.is_authenticated())  # 判断用户是否登录  如果是你们用户会返回False

# 用户登录之后 获取用户对象
print(request.user)  # 如果没有执行auth.login那么拿到的是匿名用户

# 校验用户是否登录
from django.contrib.auth.decorators import login_required
@login_required(login_url='/xxx/')  # 局部配置
def index(request):
    pass

# 全局配置  settings文件中
LOGIN_URL = '/xxx/'

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

# 修改密码	
request.user.set_password(new_password)
request.user.save()  # 修改密码的时候 一定要save保存 否则无法生效

# 退出登陆
auth.logout(request)  # request.session.flush()

# 注册用户
from django.contrib.auth.models import User
# User.objects.create(username =username,password=password)  # 创建用户名的时候 千万不要再使用create 了
# User.objects.create_user(username =username,password=password)  # 创建普通用户
User.objects.create_superuser(username=username,password=password,email='123@qq.com')  # 创建超级用户  邮箱必填
		
自定义auth_user表,我们可以再自定义表中添加新的字段,但是不要与auth_user表中的字段重复

from django.contrib.auth.models import AbstractUser
# Create your models here.
# 第一种 使用一对一关系  不考虑



# 第二种方式   使用类的继承
class Userinfo(AbstractUser):
    # 千万不要跟原来表中的字段重复 只能创新
    phone = models.BigIntegerField()
    avatar = models.CharField(max_length=32)

# 一定要在配置文件中 告诉django
# 告诉django  orm不再使用auth默认的表  而是使用你自定义的表
AUTH_USER_MODEL = 'app01.Userinfo'  # '应用名.类名'

执行数据库迁移命令
所有的auth模块功能 全部都基于你创建的表
而不再使用auth_user

原文地址:https://www.cnblogs.com/asdaa/p/11690841.html