django系列之 drf身份认证
Django中间件
1、简介
中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统,用于全局改变 Django 的输入或输出,在其他web框架中,有的叫管道或者httphandle,Django中很多功能都是通过中间件实现的,实际上中间件就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法.
django的生命周期:
nigx -->wsgi–>middleware–>urls–>views–>orm–>db
在工程中的settings.py中由变量MIDDLEWARE控制,请求从上到下依次穿过中间件,每个中间件中都可以有5个方法:
-
process_request(self,request)#请求最开始执行的方法
-
process_response(self,request, response)#请求返回时候执行的方法
-
process_view(self, request, callback,callback_args, callback_kwargs)#请求到达views视图之前执行的方法
-
process_exception(self, request, exception) # 默认不执行,除非Views方法出错
-
process_template_response(self,request,response) #
默认不执行,除非Views中的函数返回的对象中,具有render方法(区别于模板渲染的render)
类似于栈,从上往下执行,从下而上返回
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',
]
这里介绍下美国中间件的功能:
- SecurityMiddleware:为request/response提供了几种安全改进,无它不安全
- SessionMiddleware:开启session会话支持,
- CommonMiddleware:基于APPEND_SLASH和PREPEND_WWW的设置来重写URL,如果APPEND_SLASH设为True,并且初始URL 没有以斜线结尾以及在URLconf 中没找到对应定义,这时形成一个斜线结尾的新URL;如果PREPEND_WWW设为True,前面缺少 www.的url将会被重定向到相同但是以一个www.开头的url。
- CsrfViewMiddleware:添加跨站点请求伪造的保护,通过向POST表单添加一个隐藏的表单字段,并检查请求中是否有正确的值
- AuthenticationMiddleware:在视图函数执行前向每个接收到的user对象添加HttpRequest属性,表示当前登录的用户
- MessageMiddleware:开启基于Cookie和会话的消息支持
- XFrameOptionsMiddleware:对点击劫持的保护
2、请求在中间件中的方法请求过程
- 1,用户请求先中间件,由上到下先后执行每个中间件process_request方法;
- 2,执行完每个中间件的process_request方法之后,请求到达urls路由关系映射;
- 3,到达urls路由以后,由下至上执行每个中间件的process_views方法;
- 4,执行完process_views,请求到达views函数,此时若views函数有错误信息,则由下到上执行process_exception方法,直到错误发生停止;
- 5,如果views中没有出错,那么请求由下到上执行每个中间件的process_response方法,返回响应客户;
3、自定义中间件
自定义中间件,我们至少包括两个方法,一个是process_request,还有一个是process_response,创建一个py文件,在工程中创建MyMiddleWare目录(与tempates同级),创建文件md.py,注意使用process_response必须返回response:
class ApiLoggingMiddleware(MiddlewareMixin):
def process_request(self, request):
print( '''请求时执行''')
def process_response(self, request, response):
print( """视图函数调用之后,response返回浏览器之前""")
def process_exception(self, request, exception):
print('视图发生异常')
请求:127.0.0.0:8000/admin/
发生了一个错误
Traceback (most recent call last):
File "E:\py38\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "E:\py38\lib\site-packages\django\utils\deprecation.py", line 96, in __call__
response = self.process_response(request, response)
File "E:\py38\lib\site-packages\django\middleware\common.py", line 106, in process_response
if response.status_code == 404:
AttributeError: 'NoneType' object has no attribute 'status_code'
[26/Oct/2020 18:09:22] "POST /user/login/ HTTP/1.1" 500 60687
我们看一下源码
def process_response(self, request, response):
"""
When the status code of the response is 404, it may redirect to a path
with an appended slash if should_redirect_with_slash() returns True.
"""
# If the given URL is "Not Found", then check if we should redirect to
# a path with a slash appended.
if response.status_code == 404:
if self.should_redirect_with_slash(request):
return self.response_redirect_class(self.get_full_path_with_slash(request))
# Add the Content-Length header to non-streaming responses if not
# already set.
if not response.streaming and not response.has_header('Content-Length'):
response['Content-Length'] = str(len(response.content))
return response#这里必须返回response
4,源码解析
我们继承的类
class MiddlewareMixin:
def __init__(self, get_response=None):
self.get_response = get_response
super().__init__()
def __call__(self, request): #实例化后调用
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
response = response or self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
我们调用的类
class CommonMiddleware(MiddlewareMixin):
"""
"Common" middleware for taking care of some basic operations:
- Forbid access to User-Agents in settings.DISALLOWED_USER_AGENTS
- URL rewriting: Based on the APPEND_SLASH and PREPEND_WWW settings,
append missing slashes and/or prepends missing "www."s.
- If APPEND_SLASH is set and the initial URL doesn't end with a
slash, and it is not found in urlpatterns, form a new URL by
appending a slash at the end. If this new URL is found in
urlpatterns, return an HTTP redirect to this new URL; otherwise
process the initial URL as usual.
This behavior can be customized by subclassing CommonMiddleware and
overriding the response_redirect_class attribute.
"""
response_redirect_class = HttpResponsePermanentRedirect
def process_request(self, request):
"""
Check for denied User-Agents and rewrite the URL based on
settings.APPEND_SLASH and settings.PREPEND_WWW
"""
# Check for denied User-Agents
user_agent = request.META.get('HTTP_USER_AGENT')
if user_agent is not None:
for user_agent_regex in settings.DISALLOWED_USER_AGENTS:
if user_agent_regex.search(user_agent):
raise PermissionDenied('Forbidden user agent')
# Check for a redirect based on settings.PREPEND_WWW
host = request.get_host()
must_prepend = settings.PREPEND_WWW and host and not host.startswith('www.')
redirect_url = ('%s://www.%s' % (request.scheme, host)) if must_prepend else ''
# Check if a slash should be appended
if self.should_redirect_with_slash(request):
path = self.get_full_path_with_slash(request)
else:
path = request.get_full_path()
# Return a redirect if necessary
if redirect_url or path != request.get_full_path():
redirect_url += path
return self.response_redirect_class(redirect_url)
......