【一】用户权限
(1)要求
- 不同的用户,有不同的操作权限
- 比如
- 超级管理员,拥有所有权限
- 管理员可以增加、查询、修改
- 普通用户只能查询
(2)逻辑梳理
-
理论来说,这个权限需要保存在数据库中
- 但是这里只做演示,在视图函数中定义用户的权限
-
每个人的权限需要在登录以后才能获得
-
所以需要创建一个登录界面
-
在后端的登录逻辑中,根据登录的用户名进行权限查询
-
由于中间件要进行权限处理,所以这里将权限保存在session中
request.session['permission'] = permission
-
-
中间件逻辑
-
由于不是所有路径都要限制用户访问
-
所以需要白名单
pythonwhite_permission_list = ['login', 'register']
-
-
获取当前访问路径
pythonvisited_path = request.path
-
由于每次都是直接进入的根路径
- 所以将根路径也排除在外
-
循环白名单
- 使用正则匹配,在白名单的地址不进行权限要求
-
获取用户可访问的地址
pythonuser_permission_list = request.session.get("permission") user_permission_list = user_permission_list if user_permission_list else []
-
再次循环遍历可访问的地址
- 使用正则匹配,可访问的地址通过
-
到最后的就是没有权限的
- 抛出信息
(3)代码
- 中间件
python
import re
import time
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class PermissionMiddleWare(MiddlewareMixin):
"""
限制用户权限
"""
def process_request(self, request):
white_permission_list = ['login', 'register']
# 当前访问路径
visited_path = request.path
# 对根路径进行优先处理
if visited_path == "/":
return
# 对白名单路径进行处理
for white_permission in white_permission_list:
# 使用正则进行匹配
pattern = '/' + white_permission + ".*"
pattern = re.compile(pattern=pattern)
if re.search(pattern, visited_path):
return
# 获取登录用户权限
user_permission_list = request.session.get("permission")
user_permission_list = user_permission_list if user_permission_list else []
for permission in user_permission_list:
# 使用正则匹配
pattern = '/' + permission + '.*'
pattern = re.compile(pattern=pattern)
if re.search(pattern, visited_path):
return
# 前面都没有通过,那就是没有权限
return HttpResponse("你没有权限访问")
- 前端
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post">
<p>username:<input type="text" name="username"></p>
<p>password:<input type="password" name="password"></p>
<button class="button">提交</button>
</form>
<br>
<div>
<div><a href="{% url 'login' %}">登录</a></div>
<div><a href="{% url 'register' %}">注册</a></div>
<div><a href="{% url 'add_data' %}">添加</a></div>
<div><a href="{% url 'delete_data' %}">删除</a></div>
<div><a href="{% url 'revise_data' %}">修改</a></div>
<div><a href="{% url 'search_data' %}">查询</a></div>
</div>
</body>
</html>
- 视图层
python
from django.shortcuts import render, HttpResponse
user_permission_dict = {
"super": ['add_data/', 'delete_data/', 'search_data/', 'revise_data/'],
"admin": ['add_data/', 'search_data/', 'revise_data/'],
"normal": ['search_data/'],
}
def login(request):
if request.method == "POST":
# 获取用户名
username = request.POST.get("username")
# 查找用户权限,正常应该取数据库中查找,这里简化了
permission = user_permission_dict.get(username)
permission = permission if permission else []
# 保存权限
request.session['permission'] = permission
return HttpResponse("登录成功")
return render(request, 'login.html', locals())
def register(request):
return HttpResponse("注册界面")
def add_data(request):
return HttpResponse("添加界面")
def delete_data(request):
return HttpResponse("删除界面")
def revise_data(request):
return HttpResponse("修改界面")
def search_data(request):
return HttpResponse("查看界面")
- 路由层
python
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path("", views.login, name='login'),
path('register/', views.register, name='register'),
path("add_data/", views.add_data, name='add_data'),
path("delete_data/", views.delete_data, name='delete_data'),
path("search_data/", views.search_data, name='search_data'),
path("revise_data/", views.revise_data, name='revise_data'),
]
【二】IP限制访问频率
(1)要求
- 对同一个地址 在限定时间内 访问超过指定次数会抛出异常
(2)思路
-
要求是限制访问次数
- 所以这个中间件需
process_request
方法
- 所以这个中间件需
-
首先需要获取到访问的IP地址
pythonrequest.META.get("REMOTE_ADDR")
-
然后获取访问路径
pythonrequest.get_full_path()
-
然后是当前时间的获取
pythontime.time()
-
对IP进行判断
- 如果没有访问过,添加默认信息并保存
- 如果访问过
- 判断地址、判断时间
- 如果时间超过或地址变了,刷新保存信息
- 如果在时间范围内
- 访问次数+1
- 对访问次数进行判断
- 超过限定次数,返回HttpResponse信息
- 判断地址、判断时间
(3)代码
python
import time
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class SearchMiddleWare(MiddlewareMixin):
"""
对同一个地址在限定时间内访问超过指定次会抛出异常
"""
# {'127.0.0.1': {'start_time': 1711525250.3461394, 'visits': 0, "full_path": "/"}}
id_data_dict = {}
# 最大访问次数
visits_limit = 5
# 时间间隔
time_limit = 10
def process_request(self, request):
# 获取信息
user_id = request.META.get("REMOTE_ADDR")
full_path = request.get_full_path()
now_time = time.time()
# 当前IP第一次访问
if user_id not in self.id_data_dict.keys():
new_id_dict = {user_id: {"start_time": now_time, "visits": 0, "full_path": full_path}}
self.id_data_dict.update(new_id_dict)
else:
id_data = self.id_data_dict.get(user_id)
# 不是同一个地址也刷新
# 超过10秒钟重新刷新
condition = any(
[full_path != id_data.get('full_path'),
(now_time - id_data.get("start_time")) >= self.time_limit])
if condition:
id_data['start_time'] = now_time
id_data["visits"] = 0
id_data['full_path'] = full_path
self.id_data_dict.update({user_id: id_data})
# 访问间隔时间在10秒以内
if now_time - id_data.get("start_time") < self.time_limit:
# 只要来了就+1
id_data["visits"] += 1
# 十秒内访问次数超过指定次数,
if id_data['visits'] >= self.visits_limit:
return HttpResponse("访问频率过高,请稍后在尝试")