涉密档案利用不便?十分钟搭建加密审批查阅系统
一、技术方案概述
针对涉密档案“利用难、审批慢、追溯难”的痛点,本文将构建一套基于 Python Flask + SQLite + Docker 的轻量级档案利用系统。该系统核心功能包括:用户身份认证、档案申请审批流程、动态水印防泄密(自动叠加申请人信息及时间)、全链路操作日志审计。通过容器化部署,确保在任何Linux服务器上即可一键运行,无需复杂的环境配置。
二、环境准备
本系统运行依赖 Docker 环境。请确保你的服务器已安装 Docker。若未安装,请直接执行以下命令进行安装及启动:
```bash curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun systemctl start docker systemctl enable docker ```三、项目结构搭建
在服务器根目录下创建项目文件夹 secure_archive_system,并严格按照以下结构创建文件及目录:
- secure_archive_system/ (项目根目录)
- app.py (后端核心逻辑)
- requirements.txt (依赖库清单)
- Dockerfile (镜像构建文件)
- docker-compose.yml (编排部署文件)
- templates/ (前端模板目录)
- login.html (登录页)
- dashboard.html (档案列表及申请页)
- admin.html (管理员审批页)
- view.html (档案预览页)
- static/ (静态资源目录)
- uploads/ (存放涉密档案图片)
- data/ (数据库存储目录)
执行以下命令快速创建目录结构:
```bash mkdir -p secure_archive_system/{templates,static/uploads,data} cd secure_archive_system ```四、后端核心代码实现
创建 app.py 文件,该文件包含数据库初始化、水印处理逻辑、用户鉴权及业务路由。代码中已内置初始化管理员账号(admin/123456)和普通用户账号(user/123456)。
```python import os import sqlite3 import datetime from flask import Flask, render_template, request, redirect, url_for, session, send_file, Response from PIL import Image, ImageDraw, ImageFont app = Flask(__name__) app.secret_key = 'change_this_to_a_random_secret_key' DB_PATH = 'data/archive.db' UPLOAD_FOLDER = 'static/uploads' 初始化数据库 def init_db(): if not os.path.exists('data'): os.makedirs('data') conn = sqlite3.connect(DB_PATH) c = conn.cursor() 用户表 c.execute('''CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, username TEXT UNIQUE, password TEXT, role TEXT)''') 档案表 c.execute('''CREATE TABLE IF NOT EXISTS archives (id INTEGER PRIMARY KEY, title TEXT, filename TEXT, is_secret INTEGER DEFAULT 1)''') 申请表 c.execute('''CREATE TABLE IF NOT EXISTS applications (id INTEGER PRIMARY KEY, user_id INTEGER, archive_id INTEGER, status TEXT, apply_time TEXT, approve_time TEXT)''') 日志表 c.execute('''CREATE TABLE IF NOT EXISTS logs (id INTEGER PRIMARY KEY, user_id INTEGER, action TEXT, detail TEXT, timestamp TEXT)''') 初始化默认数据 try: c.execute("INSERT INTO users (username, password, role) VALUES ('admin', '123456', 'admin')") c.execute("INSERT INTO users (username, password, role) VALUES ('user', '123456', 'user')") 模拟插入一份涉密档案,请确保static/uploads下有一张名为secret_doc.jpg的图片,或者修改此处 c.execute("INSERT INTO archives (title, filename, is_secret) VALUES ('机密文件2023号', 'secret_doc.jpg', 1)") except sqlite3.IntegrityError: pass conn.commit() conn.close() 添加水印函数 def add_watermark(image_path, username): img = Image.open(image_path).convert('RGBA') txt = Image.new('RGBA', img.size, (255, 255, 255, 0)) draw = ImageDraw.Draw(txt) 尝试使用系统字体,若失败使用默认 try: font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 40) except: font = ImageFont.load_default() text_content = f"涉密查阅 - {username} - {datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}" text_width, text_height = draw.textsize(text_content, font=font) 在图片中心及四周打水印 positions = [ (10, 10), (img.size[0] - text_width - 10, img.size[1] - text_height - 10), (img.size[0] // 2 - text_width // 2, img.size[1] // 2 - text_height // 2) ] for pos in positions: draw.text(pos, text_content, font=font, fill=(255, 0, 0, 128)) watermarked = Image.alpha_composite(img, txt) return watermarked 辅助函数:日志记录 def log_action(user_id, action, detail): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("INSERT INTO logs (user_id, action, detail, timestamp) VALUES (?, ?, ?, ?)", (user_id, action, detail, datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) conn.commit() conn.close() @app.route('/') def index(): if 'user_id' in session: return redirect(url_for('dashboard')) return render_template('login.html') @app.route('/login', methods=['POST']) def login(): username = request.form['username'] password = request.form['password'] conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("SELECT FROM users WHERE username=? AND password=?", (username, password)) user = c.fetchone() conn.close() if user: session['user_id'] = user[0] session['role'] = user[3] session['username'] = user[1] log_action(user[0], '登录', '用户登录成功') return redirect(url_for('dashboard')) return "登录失败,请检查用户名密码 返回" @app.route('/dashboard') def dashboard(): if 'user_id' not in session: return redirect(url_for('index')) conn = sqlite3.connect(DB_PATH) c = conn.cursor() if session['role'] == 'admin': 管理员查看待审批列表 c.execute('''SELECT applications.id, users.username, archives.title, applications.status, applications.apply_time FROM applications JOIN users ON applications.user_id = users.id JOIN archives ON applications.archive_id = archives.id ORDER BY applications.apply_time DESC''') items = c.fetchall() return render_template('admin.html', items=items) else: 普通用户查看档案列表及自己的申请状态 c.execute("SELECT FROM archives") archives = c.fetchall() c.execute('''SELECT archives.title, applications.status FROM applications JOIN archives ON applications.archive_id = archives.id WHERE applications.user_id=?''', (session['user_id'],)) my_apps = c.fetchall() conn.close() return render_template('dashboard.html', archives=archives, my_apps=my_apps) @app.route('/apply/五、前端页面代码
在 templates 目录下创建以下四个 HTML 文件。为了保持零门槛,样式采用内联 CSS,无需额外编写 CSS 文件。
1. 登录页面
```html涉密档案利用系统
测试账号: admin/123456 (管理员) 或 user/123456 (普通用户)
```2. 用户仪表盘
```html档案利用大厅
欢迎, {{ session.username }} | 退出
可申请档案
| ID | 标题 | 操作 |
|---|---|---|
| {{ arc[0] }} | {{ arc[1] }} | 申请查阅 |
我的申请状态
-
{% for app in my_apps %}
- {{ app[0] }} - 状态: {{ app[1] }} {% endfor %}
3. 管理员审批页
```html管理员审批台
管理员: {{ session.username }} | 退出
| 申请ID | 申请人 | 档案标题 | 状态 | 申请时间 | 操作 |
|---|---|---|---|---|---|
| {{ item[0] }} | {{ item[1] }} | {{ item[2] }} | {{ item[3] }} | {{ item[4] }} | {% if item[3] == 'pending' %} 通过 | 驳回 {% else %} 已处理 {% endif %} |
4. 档案预览页
```html涉密档案预览
警告:该图片包含您的个人数字水印,严禁截屏外传!
六、容器化部署配置
为了确保系统在隔离的环境中运行,我们使用 Docker 进行封装。
1. 编写依赖文件
在项目根目录创建 requirements.txt:
```text Flask==2.0.1 Pillow==8.4.0 Werkzeug==2.0.1 ```2. 编写 Dockerfile
在项目根目录创建 Dockerfile:
```dockerfile FROM python:3.8-slim -bullseye 安装中文字体支持,否则水印中文会乱码 RUN apt-get update && apt-get install -y \ fonts-wqy-zenhei \ && rm -rf /var/lib/apt/lists/ WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple COPY . . 暴露端口 EXPOSE 5000 CMD ["python", "app.py"] ```3. 编写编排文件
在项目根目录创建 docker-compose.yml:
```yaml version: '3' services: archive-app: build: . container_name: secure_archive_system ports: - "8080:5000" volumes: - ./data:/app/data - ./static/uploads:/app/static/uploads restart: always ```七、启动与实操演示
所有配置文件已就绪,现在执行以下命令启动系统。
1. 构建并启动容器
在项目根目录 secure_archive_system 下执行:
```bash docker-compose up -d --build