一、什么是Django中间件?
1、中间件是Django处理请求/响应的钩子框架。这是一个轻,低层次的“插件”系统,用于全局改变Django和客户端的输入和输出。
2、我的理解,给Django加一个装饰器,客户端向Django发送请求时,先由中间件处理一下,再决定是否交给Views处理
3、一般处理哪些任务?请求的日志、用户登录认证、请求地址跳转、IP地址过滤,等等
二、中间件在哪里设置?
project下,project包下的settings.py文件,MIDDLEWARE列表,添加或删除列表项。
三、多个中间件的运行方式?
中间件列表运行从前到后,遇到错误停止,返回数据从后到前。类似列表的先进后出。
四、中间件在一次请求中的运行时间点?
1、Django服务启动时,中件间初始化
2、客户端请求时,中件间调用
五、自已怎么做一个中间件?
1、新建一个xxxxxx.py的python文件,可以放在Project任意位置,比如我这里新建midtest.py存到project根目录。
2、在midtest.py里创建中间件函数或类
from django.utils.deprecation import MiddlewareMixin
# 导入中间件类
class MyMiddleware(MiddlewareMixin):
# 自定义类继承中间件类
def process_request(self,request):
# 重写中间件方法
print("---process_request---")
3、把创建的中间件添加到settings.py的MIDDLEWARE列表
MIDDLEWARE=["midtest.MYMiddleware",
]
六、中间件进阶:
1、自定义中间件的五个方法和执行顺序:
process_request():客户端请求时执行,然后请求urls.py
process_view():urls.py之后,views.py之前
process_template_response():views.py之后
process_exception():捕获views.py的错误,所以是在views.py之后
process_response():在exception之后运行
2、代码实例
from django.utils.deprecation import MiddlewareMixin
class MyMiddleware(MiddlewareMixin):
# 例子中列举了所有方法,但使用的时候可以只用一个
# 当然也可以通过class MyMid: __init__和__call__来改写,参考继承的MiddelwareMixin类的写法
def process_request(self, request):
# request参数,客户端的请求
# 可以设置验证登陆、IP阻止列表等功能
# 1、-----通过session验证登陆-----
if request.path_info == '/login/': # 请求login正常执行
return
elif not request.session.get('k1', None): # 请求其它页面判断未登陆跳转到login
return redirect('/login/')
# 2、-----设置拒绝访问的客户端IP-----
refuse_ip=["172.0.0.1"]
if request.META.get('HTTP_X_FORWARDED_FOR', None): # 'HTTP_X_FORWARDED_FOR'使用反向代理时,寻找用户真实IP
ip = request.META['HTTP_X_FORWARDED_FOR']
else:
ip = request.META['REMOTE_ADDR'] # 如果'HTTP_X_FORWARDED_FOR'不存在则获取REMOTE_ADDR
if ip in refuse_ip: # 判断IP是否在拒绝列表里
return HttpResponse("干啥亏心事了,不让你登陆!")
def process_view(self, response, view_func, *args, **kwargs):
# request客户端请求
# view_func 请求的视图函数
# *args,**kwargs 请求时附带的参数
def process_exception(self, request, response):
# 如果views.py函数有报错,执行
# request客户端请求
七、CSRF中间件
跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的***方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
解决方法:
1、检查HTTP的Referer字段
2、添加校验Token
Django的CSRF校验:
1、django使用的是添加校验的Token,
2、方法一:使用的是中间件'django.middleware.csrf.CsrfViewMiddleware'
方法二:服务器向客户端发送一个加密的Token,来进行客户认证
3、HTML的From中添加标签{% csrf_token %}
4、CSRF源码:
class CsrfViewMiddleware(MiddlewareMixin):
def _accept(self, request):
request.csrf_processing_done = True
return None
def _reject(self, request, reason):
logger.warning(
'Forbidden (%s): %s', reason, request.path,
extra={
'status_code': 403,
'request': request,
}
)
return _get_failure_view()(request, reason=reason)
def _get_token(self, request):
if settings.CSRF_USE_SESSIONS:
try:
return request.session.get(CSRF_SESSION_KEY)
except AttributeError:
raise ImproperlyConfigured(
'CSRF_USE_SESSIONS is enabled, but request.session is not '
'set. SessionMiddleware must appear before CsrfViewMiddleware '
'in MIDDLEWARE%s.' % ('_CLASSES' if settings.MIDDLEWARE is None else '')
)
else:
try:
cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME]
except KeyError:
return None
csrf_token = _sanitize_token(cookie_token)
if csrf_token != cookie_token:
# Cookie token needed to be replaced;
# the cookie needs to be reset.
request.csrf_cookie_needs_reset = True
return csrf_token
def _set_token(self, request, response):
if settings.CSRF_USE_SESSIONS:
request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
else:
response.set_cookie(
settings.CSRF_COOKIE_NAME,
request.META['CSRF_COOKIE'],
max_age=settings.CSRF_COOKIE_AGE,
domain=settings.CSRF_COOKIE_DOMAIN,
path=settings.CSRF_COOKIE_PATH,
secure=settings.CSRF_COOKIE_SECURE,
httponly=settings.CSRF_COOKIE_HTTPONLY,
)
patch_vary_headers(response, ('Cookie',))
def process_request(self, request):
csrf_token = self._get_token(request)
if csrf_token is not None:
# Use same token next time.
request.META['CSRF_COOKIE'] = csrf_token
def process_view(self, request, callback, callback_args, callback_kwargs):
if getattr(request, 'csrf_processing_done', False):
return None
if getattr(callback, 'csrf_exempt', False):
return None
if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
if getattr(request, '_dont_enforce_csrf_checks', False):
return self._accept(request)
if request.is_secure():
referer = force_text(
request.META.get('HTTP_REFERER'),
strings_only=True,
errors='replace'
)
if referer is None:
return self._reject(request, REASON_NO_REFERER)
referer = urlparse(referer)
if '' in (referer.scheme, referer.netloc):
return self._reject(request, REASON_MALFORMED_REFERER)
if referer.scheme != 'https':
return self._reject(request, REASON_INSECURE_REFERER)
good_referer = (
settings.SESSION_COOKIE_DOMAIN
if settings.CSRF_USE_SESSIONS
else settings.CSRF_COOKIE_DOMAIN
)
if good_referer is not None:
server_port = request.get_port()
if server_port not in ('443', '80'):
good_referer = '%s:%s' % (good_referer, server_port)
else:
good_referer = request.get_host()
good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
good_hosts.append(good_referer)
if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
reason = REASON_BAD_REFERER % referer.geturl()
return self._reject(request, reason)
csrf_token = request.META.get('CSRF_COOKIE')
if csrf_token is None:
return self._reject(request, REASON_NO_CSRF_COOKIE)
request_csrf_token = ""
if request.method == "POST":
try:
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
except IOError:
pass
if request_csrf_token == "":
request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
request_csrf_token = _sanitize_token(request_csrf_token)
if not _compare_salted_tokens(request_csrf_token, csrf_token):
return self._reject(request, REASON_BAD_TOKEN)
return self._accept(request)
def process_response(self, request, response):
if not getattr(request, 'csrf_cookie_needs_reset', False):
if getattr(response, 'csrf_cookie_set', False):
return response
if not request.META.get("CSRF_COOKIE_USED", False):
return response
self._set_token(request, response)
response.csrf_cookie_set = True
return response
来源:oschina
链接:https://my.oschina.net/u/4346988/blog/4291313