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("6666")
    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),
]
View Code

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 == "123":
            # 设置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')
View Code

应用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)
View Code

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
]
View Code

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>
View Code

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

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>
View Code

 

转载于:https://www.cnblogs.com/LearningOnline/p/9337910.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本课程为Django第七季课程:用户登陆模块     本季课程主要实现图片的上传和展示,用户登陆账号的管理,用户账号的登陆、个人信息的修改、注销,使用邮箱地址找回密码。包含的主要知识点有:virtualenv虚拟环境、pip下载包、多app项目开发、templates模板的继承、font-awesome图标的使用、原生SQL语句和数据库交互、ORM模型和数据库交互、LayUI页面布局、jQuery实现用户交互、Ajax的异步请求、页面的块状展示数据、表格展示数据、表格的分页、数据的增改删改、Layer弹出层使用、表单的验证、照片的上传、照片的展示、图片展示的分页、照片的标准和放大、用户账号的增删改查、用户的登陆、Session和Cookie、Redis服务器的部署和基本配置、Django发送邮件等等知识点      本案例完整的演示了项目实现过程,虽然不复杂,但涉及的内容非常多,特别是前后端交互的时候,有诸多的坑等着你去踩,好在王老师全程代码呈现,带着大家一起填坑,大大提高学习效率的同时,也培养了大家良好的代码习惯,希望大家一致跟着王老师学习Python开发。 Django第八季课程课程预告:权限管理Django第九季课程课程预告:Web项目发布到阿里云 课程目标:本系列课程是从零基础开始并深入讲解Django,最终学会使用Django框架开发企业级的项目。课程知识点详细,项目实战贴近企业需求。本系列课程除了非常详细的讲解Django框架本身的知识点以外,还讲解了web开发中所需要用到的技术,学完本系列课程后,您将独立做出一个具有后台管理系统,并且前端非常优美实用的网站。对于从事一份Python Web开发相关的工作简直轻而易举。 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值