企业级端点验证中间件设计
# 企业级端点验证中间件设计
下面是一个企业级的Python中间件实现,用于验证前端请求的端点是否在后端自定义端点范围内,并提供友好的提示信息:
```python
from django.conf import settings
from django.http import JsonResponse
from django.urls import get_resolver
import re
import logging
logger = logging.getLogger(__name__)
class EndpointValidationMiddleware:
"""
企业级端点验证中间件
功能特性:
1. 动态验证请求端点是否在允许范围内
2. 支持正则表达式匹配端点模式
3. 可配置的端点白名单
4. 详细的日志记录
5. 友好的错误响应
配置说明:
在settings.py中添加:
ALLOWED_ENDPOINTS = [
r'^api/v1/.*$', # 允许所有v1 API
r'^admin/', # 允许Django admin
r'^static/', # 允许静态文件
r'^media/', # 允许媒体文件
r'^$', # 允许根路径
]
"""
def __init__(self, get_response):
self.get_response = get_response
self.allowed_endpoints = getattr(settings, 'ALLOWED_ENDPOINTS', [])
self.registered_endpoints = self._get_registered_endpoints()
logger.info(f"端点验证中间件已初始化,注册端点数: {len(self.registered_endpoints)}")
def _get_registered_endpoints(self):
"""获取所有已注册的端点模式"""
resolver = get_resolver()
patterns = []
# 递归获取所有URL模式
def extract_patterns(url_patterns, prefix=''):
for pattern in url_patterns:
if hasattr(pattern, 'url_patterns'):
# 处理include的子模式
extract_patterns(pattern.url_patterns, prefix + pattern.pattern.regex.pattern)
elif hasattr(pattern, 'pattern'):
# 处理标准模式
full_pattern = prefix + pattern.pattern.regex.pattern
# 清理模式字符串
clean_pattern = full_pattern.replace('^', '').replace('$', '')
patterns.append(clean_pattern)
extract_patterns(resolver.url_patterns)
return patterns
def _is_endpoint_allowed(self, path):
"""检查端点是否在允许范围内"""
# 1. 检查是否在注册端点中
if any(re.match(pattern, path) for pattern in self.registered_endpoints):
return True
# 2. 检查是否在配置的白名单中
if any(re.match(pattern, path) for pattern in self.allowed_endpoints):
return True
# 3. 检查是否是静态/媒体文件
if path.startswith(settings.STATIC_URL) or path.startswith(settings.MEDIA_URL):
return True
return False
def __call__(self, request):
path = request.path_info # 获取请求路径
# 跳过OPTIONS请求(CORS预检)
if request.method == 'OPTIONS':
return self.get_response(request)
# 验证端点
if not self._is_endpoint_allowed(path):
logger.warning(
f"非法端点访问 - IP: {self._get_client_ip(request)} | "
f"路径: {path} | 方法: {request.method}"
)
# 返回详细的错误响应
return JsonResponse(
{
"status": "error",
"code": "endpoint_not_allowed",
"message": "请求的端点不在服务范围内",
"details": {
"requested_endpoint": path,
"allowed_endpoints": self.allowed_endpoints,
"registered_endpoints": self.registered_endpoints[:10], # 只显示前10个
"suggestion": "请检查API文档或联系技术支持"
}
},
status=404,
headers={
'Content-Type': 'application/json',
'X-Endpoint-Validation': 'failed'
}
)
return self.get_response(request)
def _get_client_ip(self, request):
"""获取客户端真实IP地址"""
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
return x_forwarded_for.split(',')[0]
return request.META.get('REMOTE_ADDR', 'unknown')
```
## 配置说明
在Django项目的`settings.py`中添加以下配置:
```python
# 允许的端点模式列表(正则表达式)
ALLOWED_ENDPOINTS = [
r'^api/v1/.*$', # 允许所有v1 API
r'^api/v2/.*$', # 允许所有v2 API
r'^admin/', # 允许Django admin
r'^static/', # 允许静态文件
r'^media/', # 允许媒体文件
r'^$', # 允许根路径
r'^healthcheck/$', # 健康检查端点
r'^docs/', # API文档
]
# 中间件配置(放在MIDDLEWARE列表的顶部)
MIDDLEWARE = [
'your_app.middleware.EndpointValidationMiddleware',
# ... 其他中间件 ...
]
```
## 功能特点
1. **动态端点验证**:
- 自动获取所有注册的URL模式
- 支持正则表达式匹配
- 可配置的白名单系统
2. **企业级日志**:
- 记录非法访问的IP、路径和方法
- 中间件初始化时记录注册端点数量
- 详细的警告信息
3. **友好的错误响应**:
- 结构化的JSON错误响应
- 包含请求的端点和允许的端点列表
- 提供技术支持和文档建议
4. **智能跳过机制**:
- 自动跳过OPTIONS预检请求
- 允许静态文件和媒体文件
- 支持根路径和健康检查端点
5. **安全增强**:
- 客户端真实IP获取
- 自定义响应头标识验证结果
- 防止信息泄露(限制返回的注册端点数量)
## 使用场景
1. **API版本控制**:
```python
# 只允许v2和v3 API访问
ALLOWED_ENDPOINTS = [
r'^api/v2/.*$',
r'^api/v3/.*$',
]
```
2. **微服务网关**:
```python
# 只允许特定微服务的端点
ALLOWED_ENDPOINTS = [
r'^api/user-service/.*$',
r'^api/order-service/.*$',
r'^api/payment-service/.*$',
]
```
3. **生产环境保护**:
```python
# 生产环境禁用管理界面
if not settings.DEBUG:
ALLOWED_ENDPOINTS = [
r'^api/.*$',
r'^static/',
r'^media/',
# 排除admin
]
```
4. **临时维护**:
```python
# 维护期间只允许健康检查端点
if settings.MAINTENANCE_MODE:
ALLOWED_ENDPOINTS = [
r'^healthcheck/$',
]
```
## 响应示例
当请求非法端点时,返回的JSON响应:
```json
{
"status": "error",
"code": "endpoint_not_allowed",
"message": "请求的端点不在服务范围内",
"details": {
"requested_endpoint": "/api/v1/invalid-endpoint",
"allowed_endpoints": [
"^api/v1/.*$",
"^admin/",
"^static/",
"^media/",
"^$",
"^healthcheck/$",
"^docs/"
],
"registered_endpoints": [
"admin/",
"api/v1/users/",
"api/v1/products/",
"static/<path>",
"media/<path>",
"",
"healthcheck/",
"docs/"
],
"suggestion": "请检查API文档或联系技术支持"
}
}
```
## 企业级增强建议
1. **端点分析仪表板**:
```python
# 添加端点使用统计
from collections import defaultdict
class EndpointValidationMiddleware:
def __init__(self, get_response):
# ...
self.endpoint_usage = defaultdict(int)
def __call__(self, request):
# ...
path = request.path_info
self.endpoint_usage[path] += 1
# ...
```
2. **动态端点管理**:
```python
# 添加API来动态管理端点
from django.views import View
class EndpointManagementAPI(View):
def post(self, request):
# 添加新端点
new_endpoint = request.POST.get('endpoint')
if new_endpoint:
settings.ALLOWED_ENDPOINTS.append(new_endpoint)
return JsonResponse({"status": "success"})
def delete(self, request):
# 移除端点
endpoint = request.GET.get('endpoint')
if endpoint in settings.ALLOWED_ENDPOINTS:
settings.ALLOWED_ENDPOINTS.remove(endpoint)
return JsonResponse({"status": "success"})
```
3. **速率限制集成**:
```python
# 对非法请求实施速率限制
from django.core.cache import cache
class EndpointValidationMiddleware:
def __call__(self, request):
# ...
if not self._is_endpoint_allowed(path):
client_ip = self._get_client_ip(request)
cache_key = f"invalid_endpoint_{client_ip}"
count = cache.get(cache_key, 0) + 1
cache.set(cache_key, count, timeout=300)
if count > 10:
return JsonResponse(
{"error": "Too many invalid requests"},
status=429
)
# ...
```
4. **端点文档自动生成**:
```python
# 自动生成可用端点文档
def generate_endpoint_docs():
endpoints = sorted(set(
settings.ALLOWED_ENDPOINTS +
self.registered_endpoints
))
return {
"available_endpoints": endpoints,
"timestamp": datetime.now().isoformat()
}
```
这个中间件为企业级应用提供了强大的端点验证功能,通过动态端点检测、可配置的白名单系统和友好的错误响应,有效保护API服务免受非法端点访问的威胁。