为了确保系统的轻量化和易部署性,本指南采用 Python 语言进行开发。我们将使用 Flask 作为 Web 框架,SQLite 作为数据库(无需额外安装数据库服务),并利用 JWT(JSON Web Token)技术来实现永久授权机制。这种方式无需复杂的加密狗硬件,纯软件实现,代码完全可控。
确保你的系统中安装了 Python 3.8 或更高版本。打开终端,依次执行以下命令安装必要的系统库和 Python 包:
Ubuntu/Debian 系统执行:
```bash sudo apt-get update sudo apt-get install python3 python3-pip python3-venv -y ```CentOS/RHEL 系统执行:
```bash sudo yum install python3 python3-pip -y ```Windows 系统请直接从 python.org 下载安装包并勾选 "Add Python to PATH"。
为了隔离项目依赖,我们创建一个独立的目录并初始化虚拟环境。执行以下命令:
```bash mkdir archive_system cd archive_system python3 -m venv venv source venv/bin/activate Windows下使用 venv\Scripts\activate ```激活虚拟环境后,安装 Flask、JWT 扩展包以及工具库:
```bash pip install flask flask-sqlalchemy flask-jwt-extended pyjwt cryptography ```安装完成后,创建 requirements.txt 文件以便后续环境复现:
```bash pip freeze > requirements.txt ```在 archive_system 根目录下,按照以下结构创建文件夹和文件。这种结构清晰分离了配置、模型、业务逻辑和授权模块:
```text archive_system/ ├── app.py 程序入口与路由逻辑 ├── config.py 配置文件(密钥与数据库路径) ├── auth_service.py 授权核心逻辑(生成与验证永久License) ├── models.py 数据库模型定义 ├── storage/ 档案文件存储目录 └── requirements.txt 依赖列表 ```执行命令创建 storage 目录:
```bash mkdir storage ```这是本系统的核心。我们将使用非对称加密(RSA)或者高强度对称加密(HMAC)来签发 License。为了演示“永久授权”,我们将生成一个包含过期时间字段设置为“永不过期”的 JWT Token。
创建并编辑 auth_service.py,写入以下代码:
```python import jwt from datetime import datetime, timedelta from flask import jsonify 密钥配置:在生产环境中,请务必将此密钥存储在环境变量或受保护的配置文件中 SECRET_KEY = "ARCHIVE_SYSTEM_SUPER_SECRET_KEY_2024" def generate_permanent_license(client_id): """ 生成永久授权 License :param client_id: 客户端唯一标识(如机器码或公司ID) :return: 加密后的 License 字符串 """ 永久授权的核心在于将过期时间设置得非常久,或者不设置 exp 字段(视解析逻辑而定) 这里为了兼容性,设置为 100 年后过期 expiry_time = datetime.utcnow() + timedelta(days=365 100) payload = { "client_id": client_id, "type": "permanent", 授权类型标记 "scope": "full_access", 权限范围 "exp": expiry_time } 使用 HS256 算法进行签名 token = jwt.encode(payload, SECRET_KEY, algorithm="HS256") return token def validate_license(token): """ 验证 License 的有效性 :param token: 客户端提交的 License :return: (bool, dict) 验证结果和解码后的数据 """ try: decode 会自动验证 exp (过期时间) payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"]) 额外检查是否为永久授权类型 if payload.get("type") == "permanent": return True, payload else: return False, {"error": "非永久授权 License"} except jwt.ExpiredSignatureError: return False, {"error": "License 已过期"} except jwt.InvalidTokenError: return False, {"error": "无效的 License"} ```我们需要一个数据表来存储上传的档案元数据(文件名、上传时间、存储路径等)。创建并编辑 models.py:
```python from flask_sqlalchemy import SQLAlchemy from datetime import datetime db = SQLAlchemy() class ArchiveFile(db.Model): __tablename__ = 'archive_files' id = db.Column(db.Integer, primary_key=True) filename = db.Column(db.String(255), nullable=False) 原始文件名 stored_path = db.Column(db.String(500), nullable=False) 磁盘存储路径 file_size = db.Column(db.Integer) 文件大小(字节) upload_time = db.Column(db.DateTime, default=datetime.utcnow) 上传时间 uploader = db.Column(db.String(100)) 上传者标识 def to_dict(self): return { "id": self.id, "filename": self.filename, "file_size": self.file_size, "upload_time": self.upload_time.strftime("%Y-%m-%d %H:%M:%S"), "uploader": self.uploader } ```创建 config.py,设置数据库 URI 和上传文件夹限制:
```python import os basedir = os.path.abspath(os.path.dirname(__file__)) class Config: 使用 SQLite 数据库,文件名为 data.db SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data.db') SQLALCHEMY_TRACK_MODIFICATIONS = False 文件上传配置:最大 100MB MAX_CONTENT_LENGTH = 100 1024 1024 UPLOAD_FOLDER = os.path.join(basedir, 'storage') ```
接下来是核心业务逻辑 app.py。这里我们将整合授权验证、文件上传和列表查询功能:
```python import os import uuid from flask import Flask, request, jsonify, send_from_directory from werkzeug.utils import secure_filename 导入自定义模块 from config import Config from models import db, ArchiveFile from auth_service import validate_license app = Flask(__name__) app.config.from_object(Config) 初始化数据库 db.init_app(app) 允许的文件扩展名 ALLOWED_EXTENSIONS = {'pdf', 'doc', 'docx', 'txt', 'jpg', 'png', 'zip'} def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS 装饰器:用于保护需要授权的接口 def license_required(f): def decorated_function(args, kwargs): 从请求头获取 License auth_header = request.headers.get('Authorization') if not auth_header: return jsonify({"error": "未提供 License,请在 Header 中添加 Authorization 字段"}), 401 假设 Header 格式为 "Bearer系统部署后,我们需要生成一个 License 给客户端使用。我们可以编写一个简单的脚本或直接在 Python 交互式环境中生成。为了方便操作,我们在项目根目录创建一个临时脚本 gen_license.py:
```python from auth_service import generate_permanent_license 输入客户端标识,可以是公司名或服务器 ID client_id = input("请输入客户端标识 (例如: CLIENT_001): ") license_key = generate_permanent_license(client_id) print("-" 50) print(f"客户端: {client_id}") print(f"永久授权 License: {license_key}") print("-" 50) print("请妥善保存此 License,并在 API 请求头 Authorization 中使用。") ```运行该脚本:
```bash python gen_license.py ```输入标识后,你将获得一长串加密字符串,这就是该系统的永久授权密钥。只要服务端 SECRET_KEY 不变,该 License 永久有效。
所有代码准备就绪,现在启动系统并进行实际操作测试。
看到输出 Running on http://0.0.0.0:5000 表示启动成功。
我们需要使用生成的 License。假设生成的 License 是 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...。我们在终端使用 curl 命令测试上传一个测试文件 test.txt:
预期返回结果:
```json { "file_id": 1, "message": "上传成功" } ```如果不带 Header 访问,应该返回 401 错误:
```bash curl http://127.0.0.1:5000/api/files ```预期返回结果:
```json {"code": 403, "error": "未提供 License,请在 Header 中添加 Authorization 字段"} ```带上正确的 Header 访问:
```bash curl http://127.0.0.1:5000/api/files \ -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." ```预期返回结果:
```json { "files": [ { "file_size": 30, "filename": "test.txt", "id": 1, "upload_time": "2024-05-20 10:30:00", "uploader": "CLIENT_001" } ], "pages": 1, "total": 1 } ```以上步骤完成了从零到一的搭建。为了在生产环境中长期稳定运行,请注意以下最后两个关键点:
data.db,档案文件存储在 storage/ 目录。请务必设置定时任务(如 Cron)将这两个目录打包备份到远程存储或 NAS。python app.py 在前台运行。建议使用 supervisor 或 systemd 将 Flask 进程守护,确保服务器重启后服务自动拉起。至此,你已拥有一个完全自主可控、基于 Token 永久授权的档案管理系统。无需向任何厂商支付年费,License 即生成即永久有效。