Django Middleware 中间件
中间件字符串导入方式
settins.py -> MIDDLEWARE 中间件的放置位置
用户请求时,最先是从中间件,全部按顺序执行
中间件又有两种,接收和返回的
- 接收请求的中间件,request
- 返回请求的中间件, response
请求过来:
- 中间件:拦截一部分请求;比如验证session, 没有登录的 请求一些页面,跳转至登录页;(图片为中间件的请求过程.)
2 .再到 urls ,分发请求
3 .到views 视图 ,通过 CBV(dispatch反射) 和 FBV 的 get 请求 讲 template 页面渲染返回给用户; - 渲染之前 可以从数据库拿出数据,放到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>' % '
'.join(html))
结果如下:
ALLUSERSPROFILE C:ProgramData
APPDATA C:Usersl3591AppDataRoaming
COMMONPROGRAMFILES C:Program FilesCommon Files
COMMONPROGRAMFILES(X86) C:Program Files (x86)Common Files
COMMONPROGRAMW6432 C:Program FilesCommon Files
COMPUTERNAME HC
COMSPEC C:WINDOWSsystem32cmd.exe
DJANGO_SETTINGS_MODULE hc_learning.settings
DRIVERDATA C:WindowsSystem32DriversDriverData
FPS_BROWSER_APP_PROFILE_STRING Internet Explorer
FPS_BROWSER_USER_PROFILE_STRING Default
HOMEDRIVE C:
HOMEPATH Usersl3591
LOCALAPPDATA C:Usersl3591AppDataLocal
LOGONSERVER \HC
NUMBER_OF_PROCESSORS 8
ONEDRIVE C:Usersl3591OneDrive
ONLINESERVICES Online Services
OS Windows_NT
PATH D:python3.7Scripts;D:python3.7;C:Program Files (x86)IntelIntel(R) Management Engine ComponentsiCLS;C:Program FilesIntelIntel(R) Management Engine ComponentsiCLS;C:windowssystem32;C:windows;C:windowsSystem32Wbem;C:windowsSystem32WindowsPowerShellv1.0;C:Program Files (x86)IntelIntel(R) Management Engine ComponentsDAL;C:Program FilesIntelIntel(R) Management Engine ComponentsDAL;C:Program Files (x86)IntelIntel(R) Management Engine ComponentsIPT;C:Program FilesIntelIntel(R) Management Engine ComponentsIPT;C:Program Files (x86)NVIDIA CorporationPhysXCommon;C:Program FilesGitcmd;C:WINDOWSsystem32;C:WINDOWS;C:WINDOWSSystem32Wbem;C:WINDOWSSystem32WindowsPowerShellv1.0;C:WINDOWSSystem32OpenSSH;C:Program FilesIntelWiFiin;C:Program FilesCommon FilesIntelWirelessCommon;D:python3Scripts;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 FilesWindowsPowerShellModules;C:WINDOWSsystem32WindowsPowerShellv1.0Modules
PUBLIC C:UsersPublic
PYCHARM D:pycharmPyCharm 2018.3in;
PYCHARM_HOSTED 1
PYCHARM_MATPLOTLIB_PORT 59802
PYTHON3 D:python3.7python.exe
PYTHONIOENCODING UTF-8
PYTHONPATH C:Usersl3591Desktophc_learning;D:pycharmPyCharm 2018.3helperspycharm_matplotlib_backend
PYTHONUNBUFFERED 1
REGIONCODE APJ
SESSIONNAME Console
SYSTEMDRIVE C:
SYSTEMROOT C:WINDOWS
TEMP C:Usersl3591AppDataLocalTemp
TMP C:Usersl3591AppDataLocalTemp
USERDOMAIN HC
USERDOMAIN_ROAMINGPROFILE HC
USERNAME hc
USERPROFILE C:Usersl3591
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认证