中间件

一、中间件​

1.1 什么是中间件?​​

(1) Django默认自带7个中间件,中间件类似于django的门卫,数据在进入和离开时都需要经过中间件

(2) 那么中间件能干什么?
    控制用户访问频率,全局登录校验,用户访问白名单,黑名单等
    
(3) settings.py里面的中间件配置信息:
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',
]

(4) 中间件的执行规则:
    1> 数据传到后端时:按照(3)中的顺序,从上到下,依次经过这些中间件处理
    2> 当后端处理完之后,按照从下往上的执行顺序,经过这些中间件的处理之后传到前端
    3> 还有一些规则,会在下面的代码中讲

(5) 中间件中主要有几个方法:
    process_request(self,request)
    process_view(self, request, callback, callback_args, callback_kwargs)
    process_template_response(self,request,response)
    process_exception(self, request, exception)
    process_response(self, request, response)

1.2 怎么自定义中间件?

(1) 先导包(单独的py文件)
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
(2) 自定义中间件
    class Md1(MiddlewareMixin):
        def process_request(self,request):
            print("Md1请求")

        def process_response(self,request,response):
            print("Md1返回")
            return response

    class Md2(MiddlewareMixin):
        def process_request(self,request):
            print("Md2请求")
            #return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response
        
(3) 在view中定义一个视图函数
    def index(request):
        print("view函数...")
        return HttpResponse("OK")
    
(4) 在settings.py中的MIDDLEWARE里注册自定义中间件

ps:执行结果
    Md1请求
    Md2请求
    view函数...
    Md2返回
    Md1返回   
    
ps2:如果当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,然后依次返回到请求者,结果如下:
返回Md2中断的页面,后台打印如下:
    Md1请求
    Md2请求   
    Md2返回
    Md1返回
总结:
    (1) 中间件的process_request方法是在执行视图函数之前执行的。
    (2) 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
    (3) 不同中间件之间传递的request都是同一个对象。
    
    多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,
    ---> 第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,
    最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。

二、csrf(跨站请求伪造)

2.1 举个栗子🌰:

    钓鱼网站:银行转账的路径,可以拿到,然后你做一个跟银行一模一样的页面,也朝银行的接口提交数据,当用户在钓鱼网站输入对方账户名和转账金额之后,点击发送。其实内部是将对方账户换成了钓鱼网站的造假人员的账户,造成你转账转错账户的情况。

2.2 如何设置csrf_token

(1) 在form表单中应用
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="name"></p>
        <p>密码:<input type="text" name="password"></p>
        <p><input type="submit"></p>
    </form>
    
(2) Ajax中应用
<body>
<form action="" method="post">
    {% csrf_token %}
    <p>用户名:<input type="text" name="name"></p>
    <p>密码:<input type="text" name="password" id="pwd"></p>
    <p><input type="submit"></p>
</form>
<button class="btn">点我</button>
</body>
<script>
    $(".btn").click(function () {
        $.ajax({
            url: '',
            type: 'post',
            data: {
                'name': $('[name="name"]').val(),
                'password': $("#pwd").val(),
                'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()
            },
            success: function (data) {
                console.log(data)
            }
        })
    })
</script>
</html>

2.3 csrf_token使用范围

# 只想给某个视图函数加上csrf校验
from django.views.decorators.csrf import csrf_exempt,csrf_protect

# 局部禁用
@csrf_exempt
def index(request):
  pass

# 局部使用
@csrf_protect
def login(request):
  pass

# CBV比较特殊,不能单独加在某个方法上
# 只能加在类上或dispatch方法上
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect

@method_decorator(csrf_exempt,name='dispatch')  # 第一种
class Csrf_Token(View):
  @method_decorator(csrf_exempt)  # 第二种
  def dispatch(self,request,*args,**kwargs):
    res = super().dispatch(request,*args,**kwargs)
    return res
  @method_decorator(csrf_exempt)  # 这里这么写不行!!!
  def get(self,request):
    pass
  def post(self,request):
    pass

三、中间件版登录验证 

 

中间件版的登录验证需要依靠session,所以数据库中要有django_session表。

urls.py

复制代码
from app02 import views as v2
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/',v2.login),
    url(r'^home/',v2.home),
    url(r'^index/',v2.index)
]
复制代码

views.py

复制代码
from django.shortcuts import render,redirect,HttpResponse
from app02 import models
# Create your views here.
def login(request):
    error_msg=''
    if request.method=='POST':
        username=request.POST.get('username')
        password=request.POST.get('password')
        user_obj=models.User.objects.filter(username=username,password=password)
        if  user_obj:
            #设置session
            request.session['login']='ok'
            #获取用户想直接访问的URL
            url=request.GET.get('next')
            #如果有,就跳转到客户初始想访问的URL
            if not url:
                #没有则默认跳转到home页面
                url='/home/'
            return redirect(url)
        else:
            error_msg='username or password error!'
    return render(request,'login.html',{'error_msg':error_msg})

def home(request):
    return HttpResponse('<h1>这是home页面 只有登录了才能看到</h1>')

def index(request):
    return HttpResponse('<h1>这是index页面 也只有登录了才能看到<h1>')
复制代码

login.html

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆页面</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    <label for="">username:<input type="text" name="username"></label>
    <label for="">password:<input type="password" name="password"></label>
    <input type="submit" value="submit">
</form>
<h1 style="color: red">{{ error_msg }}</h1>

</body>
</html>
复制代码

middlewares.py

复制代码
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect

class Check_Login(MiddlewareMixin):
    def process_request(self,request):
        next_url=request.path_info
        if not next_url.startswith('/login/'):
            is_login=request.session.get('login','')
            if not is_login:
                return redirect('/login/?next={}'.format(next_url))
复制代码

在settings.py中注册

复制代码
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',
    'middleware.my_middleware.Check_Login',

]
复制代码
posted @ 2019-06-30 17:42  hengshan  阅读(217)  评论(0编辑  收藏  举报