Django框架之中间件

一、Django的生命周期

image

二、Django中间件介绍

1、什么是Django中间件?

在Django中,中间件(middleware)是一个轻量级、插件式的框架,用于在Django请求和响应处理过程中进行拦截、处理和转换。中间件可以在处理请求之前和之后执行特定的逻辑,允许开发者对请求和响应进行全局性的处理,而无需修改视图函数或URL配置。

简单来说,Django中间件九是Django请求/响应处理的钩子框架,是一个轻量级的、低级的 "插件"系统,用于全局改变Django的输入或输出

2、Django中间件的作用

请求来的时候需要先经过中间件才能到达真正的django后端;响应走的时候最后也需要经过中间件才能发送出去。可以说django中间件九是django的保安。

(1)请求预处理

  • 中间件可以在请求到达视图之前执行预处理操作。这包括对请求进行身份验证、URL重写、请求参数验证等。

(2)权限控制

  • 中间件可以用于实现权限控制逻辑。例如,检查用户是否已经登录,以及用户是否有权访问特定的资源。

(3)请求日志

  • 中间件可以记录请求日志,包括请求的URL、HTTP方法、IP地址等信息,用于监控应用的行为和调试问题。

(4)性能监控

  • 中间件可以实现性能监控,例如记录请求处理时间、数据库查询次数等,帮助开发者识别性能瓶颈并进行优化。

(5)响应后处理

  • 中间件可以在视图函数返回响应后对响应进行后处理。这可能包括添加额外的响应头、压缩响应内容、处理异常等。

(6)跨站请求伪造(CSRF)保护

  • Django提供了CSRF中间件,用于保护应用免受CSRF攻击。该中间件在每个POST请求中验证CSRF令牌的有效性。

(7)会话管理

  • 中间件可以处理会话管理逻辑。Django的SessionMiddleware用于管理会话,为每个用户提供唯一的会话标识符。

(8)URL重定向

  • Django的CommonMiddleware中间件处理URL重定向和404错误,可以根据设置的URL配置进行重定向或显示自定义的404页面。

(9)缓存控制

  • 中间件可以用于设置缓存控制头,以控制浏览器和代理服务器对响应的缓存行为,从而提高应用的性能和用户体验。

通过合理利用中间件,开发者可以在整个请求/响应处理周期中添加各种功能和逻辑,从而使应用更加灵活、安全和高效。

三、Django默认中间件介绍

1、django自带七个中间件

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',
]

(1)SecurityMiddleware

  • django.middleware.security.SecurityMiddleware
    • 安全中间件负责处理与网站安全相关的任务
    • 例如设置HTTP头部,防止跨站脚本攻击(XSS),点击劫持等。
    • 它可以通过配置自定义安全策略来确保网站的安全性。

(2)SessionMiddleware

  • django.contrib.sessions.middleware.SessionMiddleware
    • 会话中间件负责处理用户会话的创建之间存储和检索用户数据。
    • 它基于浏览器提供的Cookie或URL传递的会话ID进行会话跟踪,并将会话数据存储在后端数据库或缓存中,以实现用户状态的跨请求保持。

(3)CommonMiddleware

  • django.middleware.common.CommonMiddleware
    • 通用中间件提供了一些常见而关键的HTTP请求处理功能
    • 例如,根据请求的HTTP头信息设置语言、时区等。
    • 此外,它还处理静态文件的serving,包括收集静态文件,为其生成URL,并在开发模式下提供静态文件的serving。

(4)CsrfViewMiddleware

  • django.middleware.csrf.CsrfViewMiddleware
    • CSRF(Cross-Site Request Forgery)中间件用于防止跨站请求伪造攻击。
    • 它在每个POST请求中验证一个CSRF标记,确保请求是通过合法的表单提交得到的,从而保护用户免受恶意站点的攻击。

(5)AuthenticationMiddleware

  • django.contrib.auth.middleware.AuthenticationMiddleware
    • 认证中间件负责处理用户身份认证相关的任务
    • 例如将认证信息关联到请求对象上,为每个请求提供一个user对象,以便在请求处理过程中轻松地获取和使用用户身份信息。

(6)MessageMiddleware

  • django.contrib.messages.middleware.MessageMiddleware
    • 消息中间件用于在请求处理过程中存储和传递临时的、一次性的用户消息。
    • 它允许在HTTP重定向之间跨请求传递消息,例如成功或错误提示,以改善用户体验。

(7)XFrameOptionsMiddleware

  • django.middleware.clickjacking.XFrameOptionsMiddleware
    • 点击劫持中间件用于防止页面被嵌入到其他网站中,从而提供一定的点击劫持保护。
    • 它通过设置X-Frame-Options HTTP头部来限制页面的显示方式,从而防止恶意网页通过iframe等方式嵌入当前网页。

2、源码剖析(精简版)

(1)SessionMiddleware 源码

class SessionMiddleware(MiddlewareMixin):
def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
request.session = self.SessionStore(session_key)
def process_response(self, request, response):
return response

(2)CsrfViewMiddleware 源码

class CsrfViewMiddleware(MiddlewareMixin):
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):
return self._accept(request)
def process_response(self, request, response):
return response

(3) AuthenticationMiddleware 源码

class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
request.user = SimpleLazyObject(lambda: get_user(request))

四、如何自定义中间件

1、中间件五个方法

Django支持程序员自定义中间件并且暴漏给程序员五个中间件,

必须掌握的:

  • process_request
  • process_response

了解即可的:

  • process_view
  • process_template_response
  • process_exception

(1)process_request

  • 请求来的时候需要经过每一个中间件里面的process_request方法,结束的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行。
  • 如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
  • 如果该方法返回了Httpresponse对象,那么请求将不再继续往后执行,而是原路返回(与校验失败不允许访问相似)
  • process_request方法就是用来做全局相关的所有限制功能

该方法在每个请求到达视图之前被调用,可以对请求进行预处理。

  • 例如,进行身份验证、访问控制或请求日志记录等操作。

  • 它接收一个HttpRequest对象作为参数,并且没有返回值。

示例:

class AuthenticationMiddleware:
def process_request(self, request):
# 在这里进行身份验证操作
if not request.user.is_authenticated:
# 如果用户未经身份验证,则返回HttpResponse或重定向到登录页面

(2)process_response

  • 响应走的时候需要结果每一个中间件里面的process_response方法
  • 该方法必须返回一个Httpresponse对象
    • 默认返回的就是形参response,也可以自己返回自己的
  • 顺序是按照配置文件中注册了的中间件从下往上依次经过,如果没有定义的话,直接跳过执行下一个

该方法在每个请求结束并且响应返回到客户端之前被调用。

  • 可以在此处对响应进行处理
  • 例如添加额外的头信息、修改响应内容等。

它接收一个HttpRequest对象和HttpResponse对象作为参数,并且必须返回一个HttpResponse对象。

示例:

class CustomResponseMiddleware:
def process_response(self, request, response):
# 在这里对响应进行处理
response['X-Custom-Header'] = 'Custom Value'
return response

思考题:研究如果在第一个process_request方法就已经返回了Httpresponse对象,那么响应走的时候是经过所有的中间件里面的process_response方法还是有其他情况?
答案是其他情况,就是会走同级别的process_response返回

ps:flask框架也有一个中间件但是它的规律是只要返回数据了,就必须经过所有中间件里面的类似于process_response方法

(3)process_view

  • 路由匹配成功之后执行视图函数之前,会自动执行中间件里面的该方法
  • 结束的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行

该方法在请求到达视图之前被调用,在视图函数执行前执行。

  • 可以在此处进行一些操作
  • 如修改请求参数或进行记录等。

它接收一个HttpRequest对象和一个视图函数作为参数,并且可以返回一个HttpResponse对象或None。

示例:

class LoggingMiddleware:
def process_view(self, request, view_func, view_args, view_kwargs):
# 在这里记录日志
logger.info(f"Request received: {request.path}")
# 返回None,继续执行原视图函数
return None

(4)process_template_response:

  • 返回的 HttpResponse 对象有 render 属性的时候才会触发
  • 顺序是按照配置文件中注册了的中间件从下往上依次经过

该方法在视图函数返回一个TemplateResponse对象时调用。

  • 可以在此处修改模板响应
  • 例如添加全局的上下文数据或进行额外的渲染操作。

它接收一个HttpRequest对象和一个TemplateResponse对象作为参数,并且必须返回一个TemplateResponse对象。

示例:

class GlobalContextMiddleware:
def process_template_response(self, request, response):
# 在这里添加全局的上下文数据
response.context_data['global_data'] = "Global Value"
return response

(5)process_exception:

  • 当视图函数中出现异常的情况下触发
  • 顺序是按照配置文件中注册了的中间件从下往上依次经过

该方法在视图函数抛出异常时被调用。

  • 可以在此处捕获异常并进行处理
  • 例如返回一个定制的错误页面或进行日志记录等。

它接收一个HttpRequest对象和一个异常对象作为参数,可以返回一个HttpResponse对象来替代原始的异常响应。

示例:

class ErrorHandlerMiddleware:
def process_exception(self, request, exception):
# 在这里处理异常
if isinstance(exception, CustomException):
# 如果自定义异常,返回一个定制的错误页面
return render(request, 'error.html', {'error': str(exception)})
else:
# 默认情况,返回一个500服务器错误
return HttpResponseServerError("Internal Server Error")

2、自定义中间件

  • 在项目名或者应用名下创建一个任意名称的文件夹
  • 在该文件夹内创建一个任意名称的py文件
  • 在该py文件内需要书写类(这个类必须继承MiddlewareMixin),然后在这个类里面就可以自定义五个方法了(这五个方法并不是全部都需要书写,用几个写几个)
  • 需要将类的路径以字符串的形式注册到配置文件中才能生效
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',
'自己写的中间件的路径',
]

(1)process_request

  • 路由层
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/',views.index),
]
  • 视图层
def index(request):
print("这是视图函数index")
return HttpResponse("index 的返回值")
  • 配置文件
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',
# 注册自己的中间件(在应用下创建路径会有提示,但是如果在项目下创建就没有提示,需要自己根据路径书写)
'app01.mymiddle.my_middle.MyMiddle',
# 谁先注册就先执行谁
'app01.mymiddle.my_middle.MyMiddle2',
]
  • 自定义中间件
# 引入父类
from django.utils.deprecation import MiddlewareMixin
class MyMiddle(MiddlewareMixin):
def process_request(self, request):
print("这是第一个自定义中间件中的 process_request 方法")
class MyMiddle2(MiddlewareMixin):
def process_request(self, request):
print("这是第二个自定义中间件中的 process_request 方法")

(2)process_response

# 引入父类
from django.utils.deprecation import MiddlewareMixin
class MyMiddle(MiddlewareMixin):
def process_request(self, request):
print("这是第一个自定义中间件中的 process_request 方法")
def process_response(self, request, response):
'''
:param request:
:param response: 就是Django返回给浏览器的内容
:return:
'''
print("这是第一个自定义中间件中的 process_response 方法")
# 必须返回 responser
return response
  • 响应被返回的时候需要结束每一个中间件里面的 process_response 方法

    • 该方法有两个额外的参数
      • request
      • response
  • 该方法必须返回 HttpResponse 对象

    • 默认是response
    • 支持自定义
  • 顺序是按照配置文件中注册过的中间件从下往上依次经过

    • 如果没有定义,则跳过,校验下一个

(3)小结

  • 如果在第一个 process_request 方法就已经返回了 HttpResponse 对象,那么响应被返回的时候是经过所有的中间件里面的 process_response 方法还是会发生其他?

    • 会直接走同级别的 process_response 方法 ,然后直接返回
  • flask框架的中间件也有一个类似的方法

    • 但是flask返回数据就必须经过所有中间件里面的 process_response 方法

五、利用中间件思想做案例

1、引入

  • 我们在Django的配置文件中,里面的中间件配置文件,虽然使用逗号分开,但是可以做到直接引入某个模块
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',
]
  • 这种路径构造方式,我们就可以通过importlib模块实现

2、推导过程

以多平台发送消息为例

(1)引入

  • 定义一个包
def wechat(content):
print(f'微信通知:{content}')
def qq(content):
print(f'qq通知:{content}')
def email(content):
print(f'邮箱通知:{content}')
  • 启动文件中启动包
from notify import *
def send_all(content):
wechat(content)
qq(content)
email(content)
if __name__ == '__main__':
send_all('啥时候上课')
微信通知:啥时候上课
qq通知:啥时候上课
邮箱通知:啥时候上课

(2)升级

① 功能部分

  • 先分别创建不同的消息功能文件
    • 在同一个文件夹下
    • 创建三个功能文件
class Wechat(object):
def __init__(self):
# 发送微信需要做的前期准备工作
# 发送消息前的准备工作
# 比如掉接口/初始化配置等
pass
def send(self,content):
print(f'微信通知:{content}')
class QQ(object):
def __init__(self):
# 发送qq需要做的前期准备工作
# 发送消息前的准备工作
# 比如掉接口/初始化配置等
pass
def send(self,content):
print(f'qq通知:{content}')
class Email(object):
def __init__(self):
# 发送邮箱需要做的前期准备工作
# 发送消息前的准备工作
# 比如掉接口/初始化配置等
pass
def send(self,content):
print(f'邮箱通知:{content}')
  • 在上面的文件内创建初始化文件
import settings
import importlib
def send_all(content):
# 拿到每一个包的路径
for path_str in settings.MODEL_LIST:
model_path, class_name = path_str.rsplit('.', maxsplit=1)
# model_path : model.email
# class_name : email
# (1)利用字符串导入模块
# models : 模块对象
models = importlib.import_module(model_path)
# (2)利用反射拿到类名
cls = getattr(models, class_name)
# (3)生成类的对象
obj = cls()
# (4)利用鸭子类型直接调用send发送消息
obj.send(content)
if __name__ == '__main__':
send_all('1')

(3)调用部分

  • 在外部定义一个配置文件
MODEL_LIST = [
'model.email.email',
'model.QQ.QQ',
'model.WeChat.WeChat',
]
  • 在外部的真正功能文件
import model
model.send_all('这是测试消息')
email 发送的消息 :>>>这是测试消息
QQ 发送的消息 :>>>这是测试消息
WeChat 发送的消息 :>>>这是测试消息

(4)小结

  • 遵从Python中的鸭子类型
    • 可以在功能文件中自定义功能文件添加或者注释
  • settings.py 文件中相关的路径注释掉或添加上去即可

六、csrf跨站请求伪造

1、简单介绍

CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种网络攻击方式,攻击者利用用户在已登录的情况下对网站发起的请求,来执行未经用户授权的操作。攻击者通过诱使用户访问恶意网页或点击恶意链接的方式,利用用户当前的身份验证信息(如Cookie),在用户不知情的情况下向目标网站发送请求,从而执行恶意操作。

(1)攻击原理

  • 攻击者制作恶意网页或链接,诱使用户在登录状态下访问,从而触发对目标网站的请求。
  • 攻击利用了网站对用户请求的信任,因为网站无法区分是用户自己发起的请求还是攻击者伪造的请求。

(2)防御机制

  • CSRF Token:在表单提交或者每个请求中包含一个随机生成的CSRF令牌,确保请求是合法的。
  • SameSite Cookie属性:限制Cookie在跨站请求中的传递,可以设置为Strict或Lax。
  • 双重提交Cookie:在Cookie中设置一个随机生成的值,同时在请求中也包含这个值,服务器验证两者是否匹配。
  • Referer检查:检查请求的Referer头部,确保请求来源于合法的网站。
  • Custom Header:在请求中添加自定义头部,并在服务器端验证这个头部的值。

(3)Django中的CSRF保护

  • Django提供了内置的CSRF保护机制,通过在表单中添加{% csrf_token %}标签或者在Ajax请求中传递X-CSRFToken头部来保护网站免受CSRF攻击。
  • Django的CSRF保护机制会生成一个CSRF令牌,该令牌会与用户的会话相关联,确保请求是合法的。

通过有效地实施CSRF保护机制,网站可以防止恶意攻击者利用用户的身份信息发起未经授权的操作。开发者应该始终意识到CSRF攻击的威胁,并采取适当的措施来保护网站和用户数据的安全。

2、跨域请求伪造实际案例

(1)钓鱼网站

  • 搭建一个跟正规网站一模一样的界面(例如中国银行)
  • 当用户不小心点击了这个钓鱼网站,用户再次给某个人打钱
  • 打钱的操作确确实实是提交给了中国银行的系统,用户的钱也确确实实减少了
  • 但是唯一不同的时候打钱的账户不是用户想要打的账户变成了一个莫名其妙的账户

(2)内部本质

  • 首先在钓鱼网站的页面,针对对方账户,只给用户提供一个没有name属性的普通input框
  • 然后我们在内部隐藏一个已经写好name和value的input框
<h1>我是钓鱼网站</h1>
<form action="http://127.0.0.1:8000/transfer/" method="post">
<p>username: <input type="text" name="username"></p>
<p>target_user: <input type="text" ></p>
<input type="text" name="target_user" value="xiao" style="display: none">
<p>money: <input type="text" name="money"></p>
<input type="submit">
</form>
<h1>我是正经网站</h1>
<form action="/csrf/" method="post">
{# {% csrf_token %}#}
<p>username: <input type="text" name="username"></p>
<p>target_user: <input type="text" name="target_user"></p>
<p>money: <input type="text" name="money"></p>
<input type="submit">
</form>

(3)如何规避以上问题(csrf跨站请求伪造校验)

  • 网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识

  • 然后当这个页面朝后端发送post请求的时候,我的后端会先校验唯一标识

    • 如果唯一标识不对则直接拒绝(403 forbidden)

    • 如果成功则正常执行。

3、CSRF校验

(1)什么是CSRF校验?

CSRF校验(Cross-Site Request Forgery校验)是一种用于检测和防止CSRF攻击的机制。在Web应用程序中,CSRF校验通常涉及验证请求中包含的CSRF令牌是否有效,以确保请求是由合法用户发起的。

  • CSRF校验通常依赖于在Web应用程序的表单中包含一个CSRF令牌。这个令牌是一个随机生成的值,与用户的会话相关联。
  • 在进行敏感操作(如提交表单、修改数据等)时,Web应用程序会要求客户端在请求中包含这个CSRF令牌。

(2)CSRF校验过程

当用户发起请求时,Web应用程序会检查请求中是否包含有效的CSRF令牌。

如果请求中未包含CSRF令牌、CSRF令牌无效或与用户会话不匹配,Web应用程序会拒绝该请求,并可能触发CSRF错误。

(3)双重Cookie校验

后端服务器在渲染表单时,在Cookie中设置一个随机生成的CSRF 令牌,并将其存储在会话中或以其他方式关联到当前用户。

当用户提交表单时,表单数据会被一同发送到服务器,请求头或请求参数中携带一个包含CSRF 令牌的自定义字段。

后端在验证表单数据时,同时检查请求中的CSRF 令牌 和Cookie中的值是否匹配,如果不匹配,则拒绝请求。

4、如何符合校验

(1)form表单如何符合校验

  • 在form表单上面加上csrf_token
<form action="" method="post">
{% csrf_token %} # csrf没有注释掉的前提需要加这个
<p>username: <input type="text" name="username"></p>
<p>target_user: <input type="text" name="target_user"></p>
<p>money: <input type="text" name="money"></p>
<input type="submit">
</form>
  • 在页面标签中会自动出现一个标签
<input type="hidden" name="csrfmiddlewaretoken" value="zQaNPZsy1tVmLdqC7GIDOOOfR7yT9YfO58lJ5yrjZfTw2edZTrVYUllOVMnkwXKe">

(2)ajax如何符合校验

① 方式一

  • 利用标签查找获取页面上的随机字符串
  • 键必须叫 csrfmiddlewaretoken
<button id="b1">ajax请求提交</button>
<script>
$("#b1").click(function () {
$.ajax({
url: '',
type: 'post',
// (1) 利用标签查找获取页面上的随机字符串
data: {
"username": "dream",
"csrfmiddlewaretoken":$("input[name='csrfmiddlewaretoken']").val()
},
success: function () {
}
})
})
</script>

② 方式二

  • 利用模板语法进行快捷引入
<button id="b1">ajax请求提交</button>
<script>
$("#b1").click(function () {
$.ajax({
url: '',
type: 'post',
// (2) 利用模板语法提供的快捷书写
data: {
"username": "dream",
"csrfmiddlewaretoken": "{{ csrf_token }}"
},
success: function () {
}
})
})
</script>

③ 方式三

  • 定义一个js文件并引入
  • 导入该配置文件之前,需要先导入jQuery,因为这个配置文件内的内容是基于jQuery来实现的
<button id="b1">ajax请求提交</button>
// 定义外部js文件并引入到本地
<script src="{% static 'js/csrf_check.js' %}"></script>
<script>
$("#b1").click(function () {
$.ajax({
url: '',
type: 'post',
data: {
"username": "xiao"
},
success: function () {
}
})
})
</script>
  • csrf_check.js
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});

七、csrf相关装饰器

csrf相关装饰器提供给网站两种方案

  • 网站整体都不校验csrf,就单单几个视图函数需要校验
  • 网站整体都校验csrf,就单单几个视图函数不校验

可是有哪些装饰器可以供我们使用呢?

1、@csrf_protect

  • @csrf_protect装饰器用于保护特定视图免受CSRF攻击。
  • 当视图被此装饰器装饰时,Django将确保请求中包含有效的CSRF令牌。
  • 如果请求中的CSRF令牌无效或缺失,Django将拒绝该请求并返回一个CSRF错误页面。

2、@csrf_exempt

  • @csrf_exempt装饰器用于排除特定视图或视图函数免受CSRF保护。
  • 当视图被此装饰器装饰时,Django将允许请求不包含有效的CSRF令牌。
  • 这在某些情况下是有用的,例如对于公共API或其他无需CSRF保护的端点。

3、@ensure_csrf_cookie

  • @ensure_csrf_cookie装饰器用于确保在响应中设置CSRF令牌的cookie。
  • 当视图被此装饰器装饰时,Django将在响应中包含CSRF令牌的cookie。
  • 这有助于客户端在后续请求中包含正确的CSRF令牌。

4、装饰器位置

(1)FBV中使用CSRF装饰器

  • 当我们没有注释掉csrf校验中间件的时候,可以在函数头上加上 @csrf_exempt 忽视校验
  • 当我们注释掉csrf校验中间件的时候,可以在函数头上加上 @csrf_protect 强制启动校验
from django.views.decorators.csrf import csrf_protect, csrf_exempt
'''
csrf_protect 需要校验
csrf_exempt 忽视校验
'''
# @csrf_protect / @csrf_exempt
def register(request):
...

(2)CBV中使用CSRF装饰器

  • csrf_protect 需要校验
    • 针对 csrf_protect 符合之前的装饰器的三种用法
  • csrf_exempt 忽视校验
    • 针对 csrf_exempt 只能给 dispatch 方法加才有效
from django.views import View
from django.utils.decorators import method_decorator
# 针对csrf_protect 第二种方式可以
@method_decorator(csrf_protect, 'post')
# 针对csrf_exempt 第二种方式不可以
@method_decorator(csrf_exempt, 'post')
class MyCsrfToken(View):
# 针对csrf_protect 第三种方式可以
@method_decorator(csrf_protect)
# 针对csrf_exempt 第三种方式可以 只有加给dispatch才能生效
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(MyCsrfToken, self).dispatch(request, *args, **kwargs)
def get(self, request):
return HttpResponse('get')
# 针对csrf_protect 第一种方式可以
@method_decorator(csrf_protect)
# 针对csrf_exempt 第一种方式不可以
@method_decorator(csrf_exempt)
def post(self, request):
return HttpResponse('post')

八、补充知识点

importlib模块是Python中用于动态导入模块的标准库模块。它提供了一种灵活的方式来在运行时导入模块,使得开发者可以根据需要动态加载和使用模块。以下是一些importlib模块中常用的功能和类:

  1. import_module函数
    • import_module函数允许你在运行时动态导入一个模块。
    • 你可以通过传入模块的完整名称(如'os')来导入模块。
    • 使用该函数可以避免直接使用import语句,从而实现更灵活的模块导入。
from importlib import import_module
module = import_module('os')
  1. reload函数
    • reload函数用于重新加载之前已经导入的模块。
    • 这在开发过程中可能会很有用,特别是当你对模块进行了修改并希望立即看到效果时。
from importlib import reload
reload(module)
  1. find_loader函数
    • find_loader函数用于查找指定模块的加载器。
    • 加载器负责实际加载模块的工作,通过加载器可以获取有关模块的信息。
from importlib import find_loader
loader = find_loader('os')
  1. util模块
    • importlib.util模块提供了一些实用函数,例如find_spec用于查找模块的规范对象(spec)。
from importlib.util import find_spec
spec = find_spec('os')

使用importlib模块,你可以在运行时动态地加载、重新加载和管理模块,这对于某些需要在程序运行时动态加载模块的场景非常有用,比如插件系统、模块延迟加载等。

posted @   Xiao0101  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示

目录