1.定义

  一个用来处理Django的请求和响应的框架级别的钩子(函数),相对比较轻量级,并且在全局上改变django的输入与输出(使用需谨慎,否则影响性能)

  直白的说中间件就是帮助我们在视图函数执行之前和执行之后做一些额外操作

2.用处

  用户登录

  日志记录

  权限管理

  请求验证(post)

  一般对所有请求做批量处理的时候用中间件,单独对某几个函数处理直接使用装饰器

3.用法说明

  我们使用django一直就在使用中间件,打开django的setting文件,当中的MIDDLEWARE配置项

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',
]

列表当中的每个字符串,其实是一个个类,即一个个中间件,它们正常的执行顺序都是自上而下的

中间件中,我们可以定义五个方法,分别是:

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)

其中最常用的是process_request和process_response

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

3.1 图例说明

这里还是先来看看django的生命周期图例

先从上图了解django执行流程,每一步起了那些关键性作用,然后我们再来讨论每一个中间件

3.2 process_request与process_response  

  process_request有一个request参数,这个和视图函数中的request参数一模一样

  process_response有两个参数,一个是request,一个是response,request和前面一致,response是视图函数返回的HttpResponse对象

代码实例

  我在应用下创建了一个middlewares文件,用于存放中间件

from django.utils.deprecation import MiddlewareMixin
# 注意导入路径
class MD1(MiddlewareMixin): def process_request(self, request):
print('我是MD1的process_request') def process_response(self, request, response):
print('我是MD1的process_response')
return response class MD2(MiddlewareMixin): def process_request(self, request):
print('我是MD2的process_request') def process_response(self, request, response):
print('我是MD2的process_response')
return response

setting.py文件配制添加的中间价位置

访问一个视图,终端输出结果:

总结:

  1.process_request方法,是在视图函数执行之前执行的,当配制多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的

  返回值是None,继续往后执行,返回值是HttpResponse的对象,执行对应中间件的process_response方法

  2.对于视图函数,是在process_request执行完毕后开始执行的

  3.process_response方法,是在视图函数之后执行的,而且多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的

3.3 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)。

代码实例

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, redirect, HttpResponse class MD1(MiddlewareMixin): def process_request(self, request):
print('我是MD1的process_request') def process_response(self, request, response):
print('我是MD1的process_response')
return response def process_view(self, request, view_func, view_args, view_kwargs):
print('我是MD1的process_view')
print(view_func, view_func.__name__) class MD2(MiddlewareMixin): def process_request(self, request):
print('我是MD2的process_request')
# return HttpResponse('MD2process_request') def process_response(self, request, response):
print('我是MD2的process_response')
return response def process_view(self, request, view_func, view_args, view_kwargs):
print('我是MD2的process_view')
print(view_func, view_func.__name__)

效果

总结:

  1.process_view是在视图执行前执行的,process_request之后,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的

3.4 process_exception

  process_exception(self, request, exception)

该方法两个参数:

  一个HttpRequest对象

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

该方法只有在视图函数中出现异常才会执行,如果视图函数中无异常,process_exception方法不执行。

代码实例

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, redirect, HttpResponse class MD1(MiddlewareMixin): def process_request(self, request):
print('我是MD1的process_request') def process_response(self, request, response):
print('我是MD1的process_response')
return response def process_view(self, request, view_func, view_args, view_kwargs):
print('我是MD1的process_view')
print(view_func, view_func.__name__) def process_exception(self, request, exception):
print(exception, '这是MD1的process_exception')
# return HttpResponse(str(exception)) class MD2(MiddlewareMixin): def process_request(self, request):
print('我是MD2的process_request')
# return HttpResponse('MD2process_request') def process_response(self, request, response):
print('我是MD2的process_response')
return response def process_view(self, request, view_func, view_args, view_kwargs):
print('我是MD2的process_view')
print(view_func, view_func.__name__)
# return HttpResponse('这是MD2的process_view') def process_exception(self, request, exception):
print(exception, '这是MD2的process_exception')
return HttpResponse(str(exception)) # 返回一个响应对象

在视图函数index中抛出一个异常

def index(request):
print('app01中的index视图')
raise ValueError("")
return HttpResponse('这是index页面')

此时结果:

# 可以从结果看出来,exception接收的就是异常信息,我们的MD1并没有return HttpResponse(str(exception)) ,但是它却也抛出了异常信息

总结:

  1.只要视图函数报错了才执行

  2.在视图函数之后,process_response之前

3.5 process_template_response(不常用)

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

4.中间件执行流程

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

process_request方法都执行完后,匹配路由找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。假如中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

中间件的执行顺序:

5.中间件实现登录验证

  以下代码还具有阻隔功能,即必须先登录才能访问主页,直接从url访问index会拒绝请求

代码实例:

 urls.py

urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('logout/', views.logout),
path('index/', views.index),
path('home/', views.home),
]

views.py

from django.shortcuts import render, HttpResponse, redirect
from django.contrib import auth
import json # Create your views here.
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
ret = {"status": 0, 'url': ''}
if user == "xiao" and pwd == "":
# 设置session
request.session["user"] = user
ret['status'] = 1
# 跳转到index页面
ret['url'] = '/index/' return HttpResponse(json.dumps(ret)) return render(request, "login.html") def logout(request): # 注销
auth.logout(request)
return redirect("/login/") def index(request):
return HttpResponse('this is index <a href="/logout/">注销</a>') def home(request):
return HttpResponse('this is home')

应用app01下的middlewares.py

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, redirect, HttpResponse class AuthMD(MiddlewareMixin): # 验证登录
white_list = ['/login/', ] # 白名单
black_list = ['/black/', ] # 黑名单
ret = {"status": 0, 'url': '', 'msg': ''} # 默认状态 def process_request(self, request): # 请求之前
request_url = request.path_info # 获取请求路径
# get_full_path()表示带参数的路径
print(request.path_info, request.get_full_path())
# 黑名单的网址限制访问
if request_url in self.black_list:
self.ret['msg'] = "这是非法请求"
self.ret['url'] = "/login/"
# 白名单的网址或者登陆用户不做限制
# 判断是否在白名单内或者已经有了session(表示已经登录了)
elif request_url in self.white_list or request.session.get("user"):
return None
else:
self.ret['msg'] = "请登录后,再访问!"
self.ret['url'] = "/login/" # 错误页面提示
return render(request, "jump.html", self.ret)

settings.py的MIDDLEWARE配置项

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',
'app01.middlewares.AuthMD', # 自定义中间件AuthMD
]

jump.html,用来做中间件不通过时,js跳转

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<link rel="stylesheet" href="http://mishengqiang.com/sweetalert/css/sweetalert.css">
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="http://mishengqiang.com/sweetalert/js/sweetalert-dev.js"></script>
<div>
{#获取错误信息#}
<input type="hidden" id="msg" value="{{ msg }}">
<input type="hidden" id="url" value="{{ url }}">
</div> <script>
$(function () {
var msg = $("#msg").val();
var url = $("#url").val();
console.log(msg);
console.log(url); if (msg.length > 0) { //判断是否有错误信息
swal({
title: msg,
text: "2秒后自动关闭。",
type: 'error',
timer: 2000,
showConfirmButton: false
}, function () {
window.location.href = url; //跳转指定url
}); } })
</script> </body>
</html>

# 这里的定制化错误信息效果相当不错,可以拿来借鉴

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>登录</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/signin.css">
</head>
<body> <div class="container"> <form class="form-signin">
{% csrf_token %}
<h2 class="form-signin-heading">请登录</h2>
<label for="inputUser" class="sr-only">用户名</label>
<input type="text" id="inputUser" class="form-control" placeholder="用户名" required="" autofocus="" name="user">
<label for="inputPassword" class="sr-only">密码</label>
<input type="password" id="inputPassword" class="form-control" placeholder="密码" required="" name="pwd">
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> 记住我
</label>
</div>
<input class="btn btn-lg btn-primary btn-block" id="login" value="登陆">
</form> </div> <!-- /container --> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
{#必须先引入jquery,再引入cookie#}
<script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
{#sweetalert插件#}
<link rel="stylesheet" href="http://mishengqiang.com/sweetalert/css/sweetalert.css">
<script src="http://mishengqiang.com/sweetalert/js/sweetalert-dev.js"></script>
<script>
//ajax在发送之前,做的header头。csrfSafeMethod是一个方法名,用来调用的
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
//这些HTTP方法不需要CSRF保护
// 匹配method的请求模式,js正则匹配用test
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
} $('#login').click(function () {
$.ajax({
url: '/login/',
type: 'post',
//增加X-CSRFToken的请求头
headers:{ "X-CSRFToken":$.cookie('csrftoken') },
data: {
user: $('[name="user"]').val(),
pwd: $('[name="pwd"]').val()
},
success: function (data) {
data = JSON.parse(data);
if (data.status) {
swal({
title: '登录成功',
type: 'success', //展示成功的图片
timer: 500, //延时500毫秒
showConfirmButton: false //关闭确认框
}, function () {
window.location.href = data.url; //跳转后台首页
});
}
else {
sweetAlert("登录失败!", data.msg, "error");
}
}
})
})
</script> </body>
</html>

django中间件及中间件实现的登录验证的更多相关文章

  1. Django - CBV装饰器实现用户登录验证

    一.使用Django自带的decorator 通常情况,使用 函数定义的view,可以直接使用 login_required 直接装饰 @login_required def index(reques ...

  2. Django 登录验证-自动重定向到登录页

    Web项目有些场景需要做用户登录验证,以便访问不同页面. 方法一:login_required装饰器 适用于函数视图. from django.contrib.auth.decorators impo ...

  3. Django自定义User模型和登录验证

    用户表已存在(与其他App共用),不能再使用Django内置的User模型和默认的登录认证.但是还想使用Django的认证框架(真的很方便啊). 两个步骤: 1)自定义Use模型,为了区分系统的Use ...

  4. Django 中间件版登录验证

    中间件版的登录验证需要依靠session,所以数据库中要有django_session表. urls.py # urls.py from django.conf.urls import url fro ...

  5. Django通过中间件实现登录验证demo

    前提:中间件版的登录验证需要依靠session,所以数据库中要有django_session表. from django.conf.urls import url from django.contri ...

  6. 自定义Django中间件(登录验证中间件实例)

    前戏 我们在前面的课程中已经学会了给视图函数加装饰器来判断是用户是否登录,把没有登录的用户请求跳转到登录页面.我们通过给几个特定视图函数加装饰器实现了这个需求.但是以后添加的视图函数可能也需要加上装饰 ...

  7. django系列8.3--django中间件实现登录验证(1)

    中间件版的登录验证需要依靠session,所以数据库中要有django_session表. urls.py from django.conf.urls import url from app01 im ...

  8. Django框架之中间件与Auth

    Django框架之中间件与Auth模块一 cbv加装饰器 -先导入:from django.utils.decorators import method_decorator -1 可以在方法上加装饰器 ...

  9. {Django基础九之中间件} 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证

    Django基础九之中间件 本节目录 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证 六 xxx 七 xxx 八 xxx 一 前戏 我们在前面的课程中已经学会了 ...

随机推荐

  1. spring aop 原理学习

    @EnableAspectJAutoProxy: @Import(AspectJAutoProxyRegistrar.class) 实际是创建了一个以org.springframework.aop.c ...

  2. Turing Year 2012

    Turing LectureFrom cryptanalysis to cognitive neuroscience - a hidden legacy of Alan Turinghttp://co ...

  3. POI 按word模版生成合同并生成PDF

    功能需求:根据用户给的word版本合同文件.docx,实现模版替换功能. 如: 功能:支持段落和表格里的文字替换,还可以支持表格替换.如果需要段落需要换行用<br>隔开如:身份证<b ...

  4. leetcode 620. Not Boring Movies 用where语句判断

    https://leetcode.com/problems/not-boring-movies/description/ 不管题目简不简单,现在先熟悉语法. 直接用where语句判断即可,判断奇偶可以 ...

  5. C# String.Join用法

    String.Join(String, String[]) 在指定 String 数组的每个元素之间串联指定的分隔符 String,从而产生单个串联的字符串 例如: string [] array={ ...

  6. python3+Appium自动化10-日志收集

    日志概述 日志作用 日志是定位问题的重要手段 日志级别 级别 何时使用 DEBUG 调试信息,也是最详细的日志信息 INFO 证明事情按预期工作 WARNING 表明发生了一些意外,或者不就的将来(如 ...

  7. 开发安全的 API 所需要核对的清单

    开发安全的 API 所需要核对的清单 以下是当你在设计, 测试以及发布你的 API 的时候所需要核对的重要安全措施. 身份认证 不要使用 Basic Auth 使用标准的认证协议 (如 JWT, OA ...

  8. 树莓派直连线连接PC

    刚入手树莓派一天不到,SSH树莓派一直用的是路由+无线网卡的配置.想到明天就要出差了,本想把树莓派也带去,可宾馆的房间只有一个网口,通常都是兄弟们连接小型无线路由用的,连接树莓派似乎成了一个难题.于是 ...

  9. <Android 基础(十四)> selector

    介绍 A StateListDrawable is a drawable object defined in XML that uses a several different images to r ...

  10. Design Pattern ->Adaptor

    Layering & Contract Philosophy With additional indirection Adaptee object just is as a member. A ...