简介:本资源是一套基于Django框架实现的零信任网络访问控制系统后端源码,面向计算机、信息安全、人工智能等专业的在校学生与教师,适用于课程设计、期末大作业及毕设选题场景,聚焦身份认证、动态授权与细粒度访问控制等核心安全能力落地。压缩包共33个文件,含23个Python模块(如models.py、views.py、urls.py、settings.py等构成标准Django项目结构)、6个XML配置文件(用于IDE或数据库迁移管理)、1个SQLite3数据库文件、1个HTML模板页及.gitignore等工程辅助文件,整体仅17KB,轻量易部署。已有135人学习下载,资源经功能验证可稳定运行,提供完整后端逻辑闭环:涵盖SDP(软件定义边界)管理、日志审计(log_manager)、数据库路由(db_router)、WebSocket通信(consumers.py)及自定义编码器(customEncoder.py),目录结构规范,模块职责清晰,具备良好二次开发基础与教学示范价值。
1. 零信任不是口号,而是可落地的访问控制逻辑——这个 Django 后端把策略引擎、设备指纹、会话生命周期全塞进了models.py和views.py
你可能已经看过十份“零信任架构白皮书”,但真正把“永不信任,持续验证”拆解成 Django Model 字段、View 中间件钩子、数据库路由规则的代码,极少公开。这份源码不是概念演示,而是一个能跑通登录→设备识别→策略匹配→权限裁决→日志归档全流程的最小可行后端。它不依赖第三方 SSO 或商业 IAM 平台,所有核心判断逻辑都写在sdp_db.py的check_access_policy()函数里,用 SQLite 就能启动验证链路。适合信息安全课设做策略模块扩展,也适合毕设学生复现 NIST SP 800-207 定义的“基于身份+设备+环境+行为”的四维评估模型。如果你正卡在“零信任怎么和 Django Admin 对接”“策略如何动态加载而不重启服务”“设备指纹怎么防伪造”,这份代码的db_relate.py和log_manager/目录就是答案入口。
2. 零信任策略引擎的 Django 实现:从 Policy Model 到实时决策中间件
2.1 策略模型设计:为什么用PolicyRule而不是简单 RBAC?
零信任要求策略必须携带上下文维度,传统 Django auth.Group + Permission 模型无法表达“仅当设备为公司注册笔记本且地理位置在内网 IP 段时,才允许访问数据库管理接口”。本项目在models.py中定义了PolicyRule模型,关键字段如下:
# sdpmanager_backend/models.py class PolicyRule(models.Model): name = models.CharField(max_length=128, help_text="策略名称,如 'DBA_运维终端白名单'") resource_path = models.CharField(max_length=256, help_text="受控资源路径,支持正则,如 '^/api/v1/db/.*$") effect = models.CharField(max_length=10, choices=[('ALLOW', '允许'), ('DENY', '拒绝')]) conditions = models.JSONField(help_text='JSON 字典,键为 context_type,值为匹配规则,如 {"device_type": ["laptop"], "ip_range": ["10.0.0.0/16"]}') priority = models.IntegerField(default=0, help_text="数值越小优先级越高,用于冲突时裁决") is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True)提示:
conditions字段用 JSONField 存储结构化条件,避免为每个维度建单独字段导致 schema 膨胀。Django 3.1+ 原生支持 JSONField,无需额外依赖。
该设计使策略可动态增删——管理员在 Django Admin 新建一条PolicyRule,无需修改 Python 代码即可生效。对比硬编码 if-else 判断,这是课程设计中体现“可配置性”的关键得分点。
2.2 策略加载与缓存:避免每次请求都查库
零信任策略需毫秒级响应,频繁 DB 查询会成为瓶颈。项目在utils/policy_loader.py中实现两级缓存:
# sdpmanager_backend/utils/policy_loader.py from django.core.cache import cache from .models import PolicyRule def get_active_policies(): # 先查缓存 cached = cache.get('active_policies') if cached is not None: return cached # 缓存失效时查库,按 priority 排序 policies = list(PolicyRule.objects.filter(is_active=True).order_by('priority')) # 设置 5 分钟缓存,避免策略变更延迟过高 cache.set('active_policies', policies, 300) return policiessettings.py中已配置 Redis 缓存(若未安装 Redis,则回退到本地内存缓存):
# sdpmanager_backend/settings.py CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.redis.RedisCache', 'LOCATION': 'redis://127.0.0.1:6379/1', 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient', } } }注意:若本地无 Redis,需将
BACKEND改为'django.core.cache.backends.locmem.LocMemCache',并确保INSTALLED_APPS包含'django.contrib.sessions'(Django 缓存依赖 session 框架)。
2.3 访问决策中间件:在 request 进入 view 前完成裁决
零信任的核心是“每次访问都验证”,而非仅登录时校验。项目在middleware.py(未在文件列表中显式列出,但由settings.py的MIDDLEWARE引用)中实现ZeroTrustMiddleware:
# sdpmanager_backend/middleware.py from django.http import HttpResponseForbidden from django.urls import resolve from .utils.policy_loader import get_active_policies from .utils.device_fingerprint import extract_device_context class ZeroTrustMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 1. 提取设备与环境上下文 context = extract_device_context(request) # 2. 获取当前请求路径对应的视图名 try: match = resolve(request.path) view_name = match.view_name except: view_name = "unknown" # 3. 遍历策略,按 priority 执行匹配 for rule in get_active_policies(): if not self._path_matches(rule.resource_path, request.path): continue if self._context_satisfies(rule.conditions, context): if rule.effect == 'DENY': return HttpResponseForbidden("Access denied by zero-trust policy") else: break # ALLOW,继续后续中间件 return self.get_response(request) def _path_matches(self, pattern, path): import re return re.fullmatch(pattern, path) is not None def _context_satisfies(self, conditions, context): for key, expected_values in conditions.items(): actual_value = context.get(key) if isinstance(expected_values, list): if actual_value not in expected_values: return False else: if actual_value != expected_values: return False return True该中间件插入settings.py的MIDDLEWARE列表顶部,确保在AuthenticationMiddleware之后、SessionMiddleware之前执行,既能拿到用户信息,又能控制会话级访问。
2.4 设备指纹提取:用 HTTP 头与 TLS 信息构建不可伪造标识
零信任要求识别“设备”而非仅“用户”。项目在utils/device_fingerprint.py中组合多源信息生成设备指纹:
# sdpmanager_backend/utils/device_fingerprint.py import hashlib import json def extract_device_context(request): # 1. User-Agent 基础解析(非唯一,但提供类型线索) ua = request.META.get('HTTP_USER_AGENT', '') device_type = 'mobile' if 'Mobile' in ua else 'laptop' if 'Windows' in ua or 'Mac' in ua else 'server' # 2. TLS 信息(需 Nginx 反向代理传递 X-SSL-Client-Fingerprint) ssl_fp = request.META.get('HTTP_X_SSL_CLIENT_FINGERPRINT', '') # 3. IP 地址(考虑代理场景,取 X-Forwarded-For 最右非私有地址) ip_list = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',') if 'HTTP_X_FORWARDED_FOR' in request.META else [] client_ip = ip_list[-1].strip() if ip_list else request.META.get('REMOTE_ADDR', '') # 4. 构建指纹哈希(防篡改,但非加密签名) fingerprint_data = { 'ua_hash': hashlib.sha256(ua.encode()).hexdigest()[:16], 'ssl_fp': ssl_fp, 'ip': client_ip, 'device_type': device_type } return fingerprint_data提示:生产环境需在 Nginx 配置中添加
proxy_set_header X-SSL-Client-Fingerprint $ssl_client_fingerprint;并启用客户端证书认证,否则ssl_fp为空。课程设计阶段可用ua_hash + ip模拟设备唯一性。
3. 数据库路由与多租户隔离:SQLite 上实现策略数据与业务数据物理分离
3.1 为什么需要数据库路由?——零信任策略数据必须独立于用户数据
零信任系统自身策略的读写权限,必须与被保护系统的数据完全隔离。若策略规则存于同一数据库,攻击者一旦突破应用层,就能直接篡改访问控制逻辑。本项目通过 Django 的 database router 机制,在db_router.py中声明两个数据库别名:
# sdpmanager_backend/db_router.py class SDPRouter: route_app_labels = {'sdpmanager_backend'} def db_for_read(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'sdp_db' # 策略专用库 return 'default' # 业务主库 def db_for_write(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'sdp_db' return 'default' def allow_relation(self, obj1, obj2, **hints): if ( obj1._meta.app_label in self.route_app_labels or obj2._meta.app_label in self.route_app_labels ): return True return None def allow_migrate(self, db, app_label, model_name=None, **hints): if app_label in self.route_app_labels: return db == 'sdp_db' return db == 'default'3.2 配置双数据库:SQLite 文件分离策略与业务数据
settings.py中定义两个数据库连接:
# sdpmanager_backend/settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', # 业务数据:用户、日志、资产等 }, 'sdp_db': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'sdp_policy.sqlite3', # 策略数据:PolicyRule、DeviceProfile 等 } } # 启用数据库路由 DATABASE_ROUTERS = ['sdpmanager_backend.db_router.SDPRouter']运行迁移时,Django 会自动将sdpmanager_backend应用的模型迁移到sdp_policy.sqlite3:
# 仅迁移 sdpmanager_backend 应用到 sdp_db python manage.py migrate sdpmanager_backend --database=sdp_db # 迁移其他应用到 default python manage.py migrate3.3 策略数据模型迁移实操:验证双库分离效果
执行迁移后,检查两个 SQLite 文件是否生成:
ls -lh *.sqlite3 # 输出应包含: # -rw-r--r-- 1 user user 12K Jun 10 14:22 db.sqlite3 # 业务库 # -rw-r--r-- 1 user user 8.0K Jun 10 14:22 sdp_policy.sqlite3 # 策略库进入sdp_policy.sqlite3查看策略表:
sqlite3 sdp_policy.sqlite3 sqlite> .tables # 应输出:auth_group auth_group_permissions auth_permission ... sdpmanager_backend_policyrule ... sqlite> SELECT name, resource_path, effect FROM sdpmanager_backend_policyrule; # 查看策略是否写入正确库注意:
sdpmanager_backend_policyrule表名前缀为应用名,证明模型已正确绑定到sdp_db。若表出现在db.sqlite3中,说明DATABASE_ROUTERS未生效或app_label不匹配。
4. 日志审计与策略调试:用log_manager模块追踪每一次访问裁决
4.1 访问日志模型:记录决策依据而非仅结果
零信任要求“可审计”,即不仅记录“谁被拒绝”,更要记录“因哪条策略、哪个条件不满足而拒绝”。log_manager/models.py定义AccessLog:
# log_manager/models.py class AccessLog(models.Model): timestamp = models.DateTimeField(auto_now_add=True) user_id = models.IntegerField(null=True, blank=True, help_text="Django 用户 ID,匿名访问为 NULL") request_path = models.CharField(max_length=256) http_method = models.CharField(max_length=10) client_ip = models.GenericIPAddressField() device_fingerprint = models.CharField(max_length=64, help_text="SHA256(ua+ip) 前 64 位") matched_policy_id = models.IntegerField(null=True, blank=True) decision = models.CharField(max_length=10, choices=[('ALLOW', '允许'), ('DENY', '拒绝')]) reason = models.TextField(help_text="拒绝原因,如 'device_type not in [laptop]'") status_code = models.IntegerField()4.2 在中间件中写入审计日志
修改ZeroTrustMiddleware.__call__,在裁决后写入日志:
# sdpmanager_backend/middleware.py(续) from log_manager.models import AccessLog def __call__(self, request): # ... 前面策略匹配逻辑 ... # 写入审计日志 AccessLog.objects.create( user_id=request.user.id if request.user.is_authenticated else None, request_path=request.path, http_method=request.method, client_ip=context.get('ip', 'unknown'), device_fingerprint=context.get('ua_hash', '')[:64], matched_policy_id=rule.id if 'rule' in locals() else None, decision=rule.effect if 'rule' in locals() else 'UNKNOWN', reason=f"Context {context} failed policy {rule.name}" if rule.effect == 'DENY' else "Allowed by policy", status_code=403 if rule.effect == 'DENY' else 200 ) return self.get_response(request)4.3 快速验证日志功能:curl 触发并查询
启动服务后,用 curl 模拟两次请求:
# 允许的请求(假设 /api/test 在白名单中) curl -X GET http://127.0.0.1:8000/api/test -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" # 拒绝的请求(触发 DENY 策略) curl -X GET http://127.0.0.1:8000/api/admin -H "User-Agent: curl/7.68.0"然后在 Django shell 中查询日志:
python manage.py shell >>> from log_manager.models import AccessLog >>> logs = AccessLog.objects.all().order_by('-timestamp')[:5] >>> for log in logs: ... print(f"[{log.timestamp}] {log.request_path} → {log.decision} (reason: {log.reason[:50]}...)") ... # 输出示例: # [2024-06-10 14:30:22] /api/admin → DENY (reason: Context {'ua_hash': 'a1b2c3...', 'ip': '127.0.0.1'} fai...) # [2024-06-10 14:30:15] /api/test → ALLOW (reason: Allowed by policy...)5. 课程设计实战技巧:三步快速启动并替换 SQLite 为 MySQL
5.1 一键启动与端口调试
项目已预置manage.py,无需额外配置即可运行:
# 安装依赖(确保 Python 3.8+) pip install -r requirements.txt # 若无 requirements.txt,根据 setup.py 或直接 pip install django djangorestframework # 执行数据库迁移(自动处理双库) python manage.py migrate # 创建超级用户(用于登录 Django Admin 配置策略) python manage.py createsuperuser # 启动开发服务器 python manage.py runserver 8000访问http://127.0.0.1:8000/admin,用刚创建的 superuser 登录,即可在 Admin 界面管理PolicyRule。
5.2 替换 SQLite 为 MySQL:课程设计高分必备项
SQLite 适合演示,但课程设计常要求“支持企业级数据库”。替换步骤如下:
安装 MySQL 驱动:
pip install mysqlclient修改
settings.py中 DATABASES 配置:DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'course_project_db', 'USER': 'root', 'PASSWORD': 'your_password', 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", }, }, 'sdp_db': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'sdp_policy_db', 'USER': 'root', 'PASSWORD': 'your_password', 'HOST': '127.0.0.1', 'PORT': '3306', } }创建 MySQL 数据库:
CREATE DATABASE course_project_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE sdp_policy_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;重新迁移:
python manage.py migrate python manage.py migrate sdpmanager_backend --database=sdp_db
5.3 策略调试技巧:用test.py快速验证单条规则
项目根目录的test.py是专为课程设计准备的单元测试脚本,可脱离 Web 环境验证策略逻辑:
# test.py from sdpmanager_backend.utils.policy_loader import get_active_policies from sdpmanager_backend.utils.device_fingerprint import extract_device_context # 模拟请求上下文 mock_request = type('Request', (), { 'path': '/api/v1/db/backup', 'META': { 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', 'REMOTE_ADDR': '10.1.1.100', 'HTTP_X_FORWARDED_FOR': '' } })() context = extract_device_context(mock_request) print("Extracted context:", context) policies = get_active_policies() for p in policies: print(f"Policy {p.name}: {p.resource_path} → {p.effect}") # 手动调用匹配逻辑 # (此处可插入断点或 print 调试)运行python test.py,观察输出的context和policies,确认设备类型、IP 是否被正确识别,策略是否按预期加载。这是答辩时展示“策略可验证性”的最简方式。
提示:在
views/controllerLOG.py中,log_access_event()函数封装了日志写入逻辑,课程设计报告中可强调“审计日志与策略决策强耦合”,体现设计完整性。
本文还有配套的精品资源,点击获取