Django中间件和csrf
django中间件
django中间件简介
django中间件是django的门户,django自带七个中间件,每个都有各自对应的功能
五个可以自定义的方法
django不仅有自带的七个中间件,django还支持自定义中间件并提供五个可以自定义的方法
(1)process_request
(2)process_response
(3)process_view
(4)process_template_response
(5)process_excepton
django中间件的使用场景
只要是全局相关的功能都可在中间件中编写
例如:用户黑名单校验、用户访问频率校验、网站全局用户身份校验
自定义中间件
自定义中间件的步骤
1.创建一个任意名称的文件夹
2.在该文件夹内创建一个任意名称的py文件
3.在该py文件内编写中间件类
4.配置文件中注册
自定义中间件的常用方法
1.process_request
请求来的时候会从上往下依次执行配置文件中注册了的中间件里面的process_request方法,若没有则直接跳过
若该方法自己返回了HttpResponse对象,那么请求不再继续往后直接返回相应的数据
2.process_response
响应走的时候会从下往上依次执行配置文件中注册了的中间件里面的process_response方法,若没有则直接跳过
若该方法自己返回了HttpResponse对象,那么响应会替换成该HttpResponse对象数据,而不再是视图函数想要返回给客户端的数据
注意:若process_request返回了HttpResponse对象,那么会从当前位置从下往上执行每一个process_response
自定义process_request
class MyMdd1(MiddlewareMixin):
def process_request(self, request):
print('自定义中间件:from MyMdd1 process_request')
return HttpResponse('<br><br><br><h2 style="text-align:center">from MyMdd1 process_request</h2>')
class MyMdd2(MiddlewareMixin):
def process_request(self, request):
print('自定义中间件:from MyMdd2 process_request')
return HttpResponse('<br><br><br><h2 style="text-align:center">from MyMdd2 process_request</h2>')
自定义process_response
class MyMdd1(MiddlewareMixin):
def process_response(self, request, response):
print('自定义中间件:from MyMdd1 process_response')
return response # response就是视图函数返回给客户端的数据
class MyMdd2(MiddlewareMixin):
def process_response(self, request, response):
print('自定义中间件:from MyMdd2 process_response')
return HttpResponse('<br><br><br><h2 style="text-align:center">稍等,容我表演5分钟</h2>')
需要了解的方法
1.process_view
路由匹配成功之后执行视图之前从上往下执行配置文件中注册了的中间件里面的process_view方法
2.process_template_response
视图函数执行完毕之后返回的对象中含有render属性对应一个render方法
则会从下往上执行配置文件中注册了的中间件里面的process_template_response方法
3.process_exception
视图函数执行过程中报错并在返回响应的时候会从下往上执行配置文件中注册了的中间件里面的process_exception
自定义process_view方法
class MyMdd1(MiddlewareMixin):
def process_view(self, request, view_func, view_args, view_kwargs):
print('view_func', view_func)
print('view_args', view_args)
print('view_kwargs', view_kwargs)
print('自定义中间件:from MyMdd1 process_view')
class MyMdd2(MiddlewareMixin):
def process_view(self, request, view_func, view_args, view_kwargs):
print('view_func', view_func) # 即将要执行的视图函数名
print('view_args', view_args) # 传给视图函数的位置参数
print('view_kwargs', view_kwargs) # 传给视图函数的关键字参数
print('自定义中间件:from MyMdd2 process_view')
自定义process_template_response方法
class MyMdd1(MiddlewareMixin):
def process_template_response(self, request, response):
print('自定义中间件:from MyMdd1 process_template_response')
return response
class MyMdd2(MiddlewareMixin):
def process_template_response(self, request, response):
print('自定义中间件:from MyMdd2 process_template_response')
return response
自定义process_exception方法
class MyMdd1(MiddlewareMixin):
def process_exception(self, request, exception):
print(exception)
print('自定义中间件:from MyMdd1 process_exception')
class MyMdd2(MiddlewareMixin):
def process_exception(self, request, exception):
print(exception)
print('自定义中间件:from MyMdd2 process_exception')
csrf
csrf简介
csrf,中文名,跨站请求伪造。csrf是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法,利用的是网站对用户网页浏览器的信任。
csrf解决策略
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'jquery-3.6.0.js' %}"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<br><br><br>
<form action="" method="post">
{% csrf_token %}
<p>当前账户:<input type="text" name="current_user"></p>
<p>目标账户:<input type="text" name="target_user"></p>
<p>转账金额:<input type="text" name="money"></p>
<input type="submit">
</form>
</div>
</div>
</div>
</body>
</html>
def test_csrf(request):
if request.method == 'POST':
current_user = request.POST.get('current_user')
target_user = request.POST.get('target_user')
money = request.POST.get('money')
return HttpResponse(f'<br><br><br><h2 style="text-align:center">用户{current_user}给用户{target_user}转账{money}元</h2>')
return render(request, 'test_csrf.html')
csrf相关装饰器
忽略csrf校验
csrf_exempt
开启csrf校验
csrf_protect
用于FBV的csrf装饰器
# @csrf_exempt # 忽略csrf校验
@csrf_protect # 开启csrf校验
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
is_user = models.User.objects.filter(username=username).first()
if is_user:
user_obj = is_user
if password == user_obj.password:
path = request.GET.get('next')
print(path)
if path:
res = redirect(path)
res.set_signed_cookie('username', '%s' % username, salt='reserve', max_age=30)
return res
else:
res = redirect('/home/')
res.set_signed_cookie('username', '%s' % username, salt='reserve', max_age=30)
return res
return HttpResponse('<br><br><br><h3 style="text-align:center">密码错误</h3>')
return HttpResponse('<br><br><br><h3 style="text-align:center">用户不存在</h3>')
return render(request, 'login.html')
用于CBV的csrf装饰器
from django import views
from django.utils.decorators import method_decorator
# @method_decorator(csrf_exempt, name='post') # 无效
class MyLogin(views.View):
# @method_decorator(csrf_exempt, name='post') # 无效
def post(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
is_user = models.User.objects.filter(username=username).first()
if is_user:
user_obj = is_user
if password == user_obj.password:
path = request.GET.get('next')
print(path)
if path:
res = redirect(path)
res.set_signed_cookie('username', '%s' % username, salt='reserve', max_age=30)
return res
else:
res = redirect('/home/')
res.set_signed_cookie('username', '%s' % username, salt='reserve', max_age=30)
return res
return HttpResponse('<br><br><br><h3 style="text-align:center">密码错误</h3>')
return HttpResponse('<br><br><br><h3 style="text-align:center">用户不存在</h3>')
def get(self, request):
return render(request, 'login.html')
@method_decorator(csrf_exempt, name='post') # 有效
def dispatch(self, request, *args, **kwargs):
return super(MyLogin, self).dispatch(request, *args, **kwargs)
基于中间件思想编写项目
importlib模块
可以通过字符串的形式导入模块
发送提示信息案例
方式1:封装成函数
点击查看func.py代码
def send_msg(msg):
print('短信信息提示:%s' % msg)
def send_qq(msg):
print('qq信息提示:%s' % msg)
def send_email(msg):
print('邮箱信息提示:%s' % msg)
def send_all(msg):
send_email(msg)
send_msg(msg)
send_qq(msg)
点击查看run.py代码
from common.func import send_all
send_all('hello world!')
方式2:封装成配置
点击查看func_set\__init__.py代码
import settings
import importlib
def send_all(msg):
# 循环获取配置文件中字符串信息
for str_path in settings.NOTIFY_FUNC_LIST:
# 切割路径信息
module_path, class_str_name = str_path.rsplit('.', maxsplit=1)
# 根据module_path导入模块文件
module = importlib.import_module(module_path)
# 利用反射获取模块文件中对应的类名
class_name = getattr(module, class_str_name)
# 实例化
obj = class_name()
# 调用发送消息的功能
obj.send(msg)
点击查看func_set\email.py代码
class Email(object):
def __init__(self):
pass
def send(self, msg):
print('邮箱提醒:%s' % msg)
点击查看func_set\qq.py代码
class QQ(object):
def __init__(self):
pass
def send(self , msg):
print('qq提示:%s' % msg)
点击查看func_set\WeChat.py代码
name = 'phone'
class WeChat(object):
def __init__(self):
pass # 发送微信提示需要提前准备的操作
def send(self,msg):
print('微信提示:%s' % msg)
点击查看setting.py代码
NOTIFY_FUNC_LIST = [
'func_set.email.Email',
'func_set.qq.QQ',
'func_set.WeChat.WeChat',
]
点击查看run.py代码
import func_set
if __name__ == '__main__':
func_set.send_all('hello world!')