Django Middleware 中间件

Django  Middleware 中间件

中间件字符串导入方式
settins.py -> MIDDLEWARE 中间件的放置位置

用户请求时,最先是从中间件,全部按顺序执行
中间件又有两种,接收和返回的

  1. 接收请求的中间件,request
  2. 返回请求的中间件, response

请求过来:

  1. 中间件:拦截一部分请求;比如验证session, 没有登录的 请求一些页面,跳转至登录页;(图片为中间件的请求过程.)
    2 .再到 urls ,分发请求
    3 .到views 视图 ,通过 CBV(dispatch反射) 和 FBV 的 get 请求 讲 template 页面渲染返回给用户;
  2. 渲染之前 可以从数据库拿出数据,放到render 的参数里面传递过去, locals() 表示 把所有参数传递
    还可以 实例化 其他 form 类,并渲染给前端
  • 可以应用于:
    • 请求日志
    • 用户登录认证
    • 各种跳转
    • 防火墙

自定义中间件

settins.py -> MIDDLEWARE 先去注册到里面才可以应用
django 1.11 以后
form djang.utils.deprecation import MiddlewareMixin
这个就没了,需要手动自己写到你的自定义的文件里去

settings.py

from django.middleware.common import CommonMiddleware

white_list = ['/login_demo/']   # 白名单机制, 不用验证session 信息

#中间件
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',
    'md.middleware.MiddlewareLogin',   # 注册
]

自定义的 中间件 -> middleware.py

class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        if not response:
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response


#自己写的中间件需要 手动去继承它 MiddlewareMixin

class Middleware_hc_login(MiddlewareMixin):
    def process_request(self, request):
        print ('你需要自定义的代码,写在这')
        if not request.META.get('PATH_INFO') in white_list:
            if not request.session.get('login'):
                return redirect('/login')

    def process_response(self, response):
        print ('这个是你的response返回,必须最后带上return返回')
        print ('一般可以不写这个response,只要写request就可以了')
        return response 

白名单机制

white_list = ['/login']      #  如果是登录的话,这个白名单就不会判断session

if not request.META.get('PATH_INFO') in white_list:
    if not request.session.get('login'):
        return redirect('/login')

关于请求头部信息

Header 和 request.META
request.META 是一个Python字典,包含了所有本次HTTP请求的Header信息,比如用户IP地址和用户Agent(通常是浏览器的名称和版本号)。 注意,Header信息的完整列表取决于用户所发送的Header信息和服务器端设置的Header信息。

这个字典中几个常见的键值有:

HTTP_REFERER
进站前链接网页,如果有的话。 (请注意,它是REFERRER的笔误。)

HTTP_USER_AGENT
用户浏览器的user-agent字符串,如果有的话。 例如: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17" .

REMOTE_ADDR
客户端IP,如:"12.345.67.89" 。(如果申请是经过代理服务器的话,那么它可能是以逗号分割的多个IP地址,如:"12.345.67.89,23.456.78.90" 。)

那么 request.META 里面还有什么有用的数据呢?动手写一个简单的view函数来显示 request.META 的所有数据,这样你就知道里面有什么了。

def display_meta(request):
    values = request.META.items()
    values.sort()
    html = []
    for k, v in values:
        html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
    return HttpResponse('<table>%s</table>' % '\n'.join(html))

结果如下:

ALLUSERSPROFILE C:\ProgramData
APPDATA C:\Users\l3591\AppData\Roaming
COMMONPROGRAMFILES  C:\Program Files\Common Files
COMMONPROGRAMFILES(X86) C:\Program Files (x86)\Common Files
COMMONPROGRAMW6432  C:\Program Files\Common Files
COMPUTERNAME    HC
COMSPEC C:\WINDOWS\system32\cmd.exe
DJANGO_SETTINGS_MODULE  hc_learning.settings
DRIVERDATA  C:\Windows\System32\Drivers\DriverData
FPS_BROWSER_APP_PROFILE_STRING  Internet Explorer
FPS_BROWSER_USER_PROFILE_STRING Default
HOMEDRIVE   C:
HOMEPATH    \Users\l3591
LOCALAPPDATA    C:\Users\l3591\AppData\Local
LOGONSERVER \\HC
NUMBER_OF_PROCESSORS    8
ONEDRIVE    C:\Users\l3591\OneDrive
ONLINESERVICES  Online Services
OS  Windows_NT
PATH    D:\python3.7\Scripts\;D:\python3.7\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\iCLS\;C:\Program Files\Intel\Intel(R) Management Engine Components\iCLS\;C:\windows\system32;C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\Git\cmd;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;D:\python3\Scripts\;D:\python3\
PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PLATFORMCODE    KV
PROCESSOR_ARCHITECTURE  AMD64
PROCESSOR_IDENTIFIER    Intel64 Family 6 Model 142 Stepping 10, GenuineIntel
PROCESSOR_LEVEL 6
PROCESSOR_REVISION  8e0a
PROGRAMDATA C:\ProgramData
PROGRAMFILES    C:\Program Files
PROGRAMFILES(X86)   C:\Program Files (x86)
PROGRAMW6432    C:\Program Files
PSMODULEPATH    C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
PUBLIC  C:\Users\Public
PYCHARM D:\pycharm\PyCharm 2018.3\bin;
PYCHARM_HOSTED  1
PYCHARM_MATPLOTLIB_PORT 59802
PYTHON3 D:\python3.7\python.exe
PYTHONIOENCODING    UTF-8
PYTHONPATH  C:\Users\l3591\Desktop\hc_learning;D:\pycharm\PyCharm 2018.3\helpers\pycharm_matplotlib_backend
PYTHONUNBUFFERED    1
REGIONCODE  APJ
SESSIONNAME Console
SYSTEMDRIVE C:
SYSTEMROOT  C:\WINDOWS
TEMP    C:\Users\l3591\AppData\Local\Temp
TMP C:\Users\l3591\AppData\Local\Temp
USERDOMAIN  HC
USERDOMAIN_ROAMINGPROFILE   HC
USERNAME    hc
USERPROFILE C:\Users\l3591
WINDIR  C:\WINDOWS
RUN_MAIN    true
SERVER_NAME hc
GATEWAY_INTERFACE   CGI/1.1
SERVER_PORT 8000
REMOTE_HOST 
CONTENT_LENGTH  
SCRIPT_NAME 
SERVER_PROTOCOL HTTP/1.1
SERVER_SOFTWARE WSGIServer/0.2
REQUEST_METHOD  GET
PATH_INFO   /meta
QUERY_STRING    
REMOTE_ADDR 127.0.0.1
CONTENT_TYPE    text/plain
HTTP_HOST   127.0.0.1:8000
HTTP_CONNECTION keep-alive
HTTP_CACHE_CONTROL  max-age=0
HTTP_UPGRADE_INSECURE_REQUESTS  1
HTTP_USER_AGENT Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0
HTTP_ACCEPT text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*'/'*;q=0.8
HTTP_ACCEPT_ENCODING    gzip, deflate, sdch, br
HTTP_ACCEPT_LANGUAGE    zh-CN,zh;q=0.8
HTTP_COOKIE csrftoken=AOFQMm36wEvD2Y2TrPgnS4RhBWRo3kcic1UScGKDFZ7sUJDOQfGgBlX1HKqZY1CN
wsgi.input  <_io.BufferedReader name=996>
wsgi.errors <_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>
wsgi.version    (1, 0)
wsgi.run_once   False
wsgi.url_scheme http
wsgi.multithread    True
wsgi.multiprocess   False
wsgi.file_wrapper   

解析客户端IP 并判断是否存在代理

通常访问者的IP就在其中,所以我们可以用下列方法获取用户的真实IP:

#X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,
#只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。

def get_ip(request):
   
     x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    
     if x_forwarded_for:
        
           ip = x_forwarded_for.split(',')[0]     #所以这里是真实的ip
    
     else:
        
           ip = request.META.get('REMOTE_ADDR')#这里获得代理ip
    return ip

扩展


中间件运用
-权限
-用户登录验证
-django的csrf_token 如何实现
csrf_token 验证在 process_view 方法里面
检查 视图是否被 @csrf_exempt (免除csrf认证)
去请求体 或 cookie 中获取token

两种 设置的方式
一种通过 装饰器
一种通过 中间件


1. process_request # 进
2. prrcess_view # 视图
3. process_response # 出
4. process_exception # 处理异常
5. process_render_template # 如果有template方法就会返回

 

请求流程

用户 -> process_request -> url路由匹配到了,但没执行 -> 跳转回中间件开头再从头走一遍到到 -> process_request -> 再到执行的views视图执行

执行完定义的逻辑 从 process_response 出去
如果中间有异常 会直接走 process_exception 处理返回异常
如果有template 就会走 process_render_template


from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_protect # 需要验证csrf_token认证
@csrf_exempt # 免除csrf_token认证

 

 
posted @ 2019-04-23 17:55  H·c  阅读(389)  评论(0编辑  收藏  举报