django中间件及中间件实现的登录验证
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中间件及中间件实现的登录验证的更多相关文章
- Django - CBV装饰器实现用户登录验证
一.使用Django自带的decorator 通常情况,使用 函数定义的view,可以直接使用 login_required 直接装饰 @login_required def index(reques ...
- Django 登录验证-自动重定向到登录页
Web项目有些场景需要做用户登录验证,以便访问不同页面. 方法一:login_required装饰器 适用于函数视图. from django.contrib.auth.decorators impo ...
- Django自定义User模型和登录验证
用户表已存在(与其他App共用),不能再使用Django内置的User模型和默认的登录认证.但是还想使用Django的认证框架(真的很方便啊). 两个步骤: 1)自定义Use模型,为了区分系统的Use ...
- Django 中间件版登录验证
中间件版的登录验证需要依靠session,所以数据库中要有django_session表. urls.py # urls.py from django.conf.urls import url fro ...
- Django通过中间件实现登录验证demo
前提:中间件版的登录验证需要依靠session,所以数据库中要有django_session表. from django.conf.urls import url from django.contri ...
- 自定义Django中间件(登录验证中间件实例)
前戏 我们在前面的课程中已经学会了给视图函数加装饰器来判断是用户是否登录,把没有登录的用户请求跳转到登录页面.我们通过给几个特定视图函数加装饰器实现了这个需求.但是以后添加的视图函数可能也需要加上装饰 ...
- django系列8.3--django中间件实现登录验证(1)
中间件版的登录验证需要依靠session,所以数据库中要有django_session表. urls.py from django.conf.urls import url from app01 im ...
- Django框架之中间件与Auth
Django框架之中间件与Auth模块一 cbv加装饰器 -先导入:from django.utils.decorators import method_decorator -1 可以在方法上加装饰器 ...
- {Django基础九之中间件} 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证
Django基础九之中间件 本节目录 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证 六 xxx 七 xxx 八 xxx 一 前戏 我们在前面的课程中已经学会了 ...
随机推荐
- Django-1 简介
1.1 MVC与MTV模型 MVCWeb服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的.松耦合的方式连接在一起,模型负 ...
- listview适配器中的控件的点击事件并传值
@Override public View getView(final int position, View convertView, ViewGroup parent) { // TODO Auto ...
- Murano py27和py34的兼容处理
tox.ini envlist = py27,py34,pep8 1. django.utils.encoding.force_unicode替换成django.utils.encoding.forc ...
- 本机访问其它电脑上的oracle数据库
最近发现很多人问到怎么才能访问别人机子上的oracle,这里来给大家做个示范 借助工具的话,oracle就自己带了两个配置和移值助手下面:net configuration assistant 和ne ...
- python 钩子函数
python 在windows下监听键盘按键 使用到的库 ctypes(通过ctypes来调用Win32API, 主要就是调用钩子函数) 使用的Win32API SetWindowsHookEx(), ...
- LinuxOS
Linux 操作系统必须完成的两个主要目的 与硬件部分交互, 为包含在硬件平台上的所有底层可编程部件提供服务 为运行在计算机系统上的应用程序(即所谓的用户空间)提供执行环境 一些操作系统运行所有的用户 ...
- android finish和system.exit(0)的区别
finish是Activity的类,仅仅针对Activity,当调用finish()时,只是将活动推向后台,并没有立即释放内存,活动的资源并没有被清理:当调用System.exit(0)时,杀死了整个 ...
- Java 之 Serializable 序列化和反序列化的概念,作用的通俗易懂的解释
遇到这个 Java Serializable 序列化这个接口,我们可能会有如下的问题a,什么叫序列化和反序列化b,作用.为啥要实现这个 Serializable 接口,也就是为啥要序列化c,seria ...
- JavaSE之Java基础(1)
1.为什么重写equals还要重写hashcode 首先equals与hashcode间的关系是这样的: 1.如果两个对象相同(即用equals比较返回true),那么它们的hashCode值一定要相 ...
- gof23 适配器模式
namespace Adapter { class Program { static void Main(string[] args) { //原实现 ClassBase customa = new ...