从零构建遗嘱数字档案馆系统完整代码与部署

系统架构与环境准备

本系统采用Node.js作为后端运行环境,MongoDB作为数据存储引擎,利用AES-256-GCM算法对遗嘱内容进行高强度加密存储。系统核心包含数据加密层、持久化层和API交互层。在开始编码前,必须确保开发环境已安装以下基础组件。

1. 安装Node.js

请确保安装了Node.js v16.0及以上版本。如果尚未安装,请使用NVM(Node Version Manager)进行安装,命令如下:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

nvm install --lts

2. 安装并启动MongoDB

为了保证环境一致性,推荐使用Docker容器快速启动MongoDB服务。执行以下命令拉取镜像并启动容器,映射端口至本地27017:

docker run -d -p 27017:27017 --name will-mongo -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=secret123 mongo:latest

执行完毕后,使用docker ps确认容器运行正常。

项目初始化与依赖安装

在本地创建项目目录并初始化Node.js项目。我们将创建一个名为will-archive-system的文件夹,并配置必要的依赖包。

1. 创建项目目录

mkdir will-archive-system && cd will-archive-system

npm init -y

2. 安装核心依赖

执行以下命令安装Express框架、MongoDB驱动(Mongoose)、加密库及跨域处理中间件:

npm install express mongoose cors body-parser dotenv crypto

其中crypto为Node.js内置模块,无需安装,但为了代码提示清晰,建议在TypeScript项目中引入类型定义,本指南使用原生JavaScript。

3. 配置环境变量

在项目根目录下创建.env文件,用于存放数据库连接字符串和加密密钥盐值。内容如下:


PORT=3000
MONGO_URI=mongodb://admin:secret123@localhost:27017/will_db?authSource=admin
ENCRYPTION_KEY=your-super-secret-32-byte-key-string

数据模型与数据库连接

我们需要定义一个严格的数据模型来存储遗嘱信息。为了安全起见,数据库中仅存储加密后的密文、初始化向量(IV)以及用于完整性校验的哈希值,绝不存储明文。

1. 创建数据模型文件

从零构建遗嘱数字档案馆系统完整代码与部署

在根目录下创建models文件夹,并新建Will.js文件:


const mongoose = require('mongoose');
const WillSchema = new mongoose.Schema({
testatorName: { type: String, required: true }, // 立遗嘱人姓名
encryptedContent: { type: String, required: true }, // AES加密后的密文
iv: { type: String, required: true }, // 初始化向量
authHash: { type: String, required: true }, // 内容哈希,用于验证解密后完整性
createdAt: { type: Date, default: Date.now },
status: { type: String, default: 'ACTIVE', enum: ['ACTIVE', 'REVOKED'] }
});
module.exports = mongoose.model('Will', WillSchema);

2. 配置数据库连接

在根目录下创建db.js,编写数据库连接逻辑:


const mongoose = require('mongoose');
require('dotenv').config();
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI);
console.log('MongoDB Connected Successfully');
} catch (err) {
console.error('Database Connection Error:', err.message);
process.exit(1);
}
};
module.exports = connectDB;

核心加密解密工具类开发

这是系统的安全核心。我们将创建一个工具类封装AES-256-GCM的加密与解密逻辑。AES-256-GCM模式不仅提供保密性,还提供数据完整性校验。

在根目录下创建utils文件夹,新建crypto.js


const crypto = require('crypto');
const algorithm = 'aes-256-gcm';
const keyLength = 32;
const saltLength = 16;
const ivLength = 16;
const tagLength = 16;
// 密钥派生函数:使用PBKDF2从环境变量密钥生成固定长度的Key
function getKeyFromPassword(password, salt) {
return crypto.pbkdf2Sync(password, salt, 100000, keyLength, 'sha256');
}
// 加密函数
exports.encrypt = (text) => {
const iv = crypto.randomBytes(ivLength);
const salt = crypto.randomBytes(saltLength);
const key = getKeyFromPassword(process.env.ENCRYPTION_KEY, salt);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag(); // 获取认证标签
// 返回格式:salt + iv + authTag + encrypted
return {
content: encrypted,
iv: iv.toString('hex'),
salt: salt.toString('hex'),
authTag: authTag.toString('hex')
};
};
// 解密函数
exports.decrypt = (encryptedContent, ivHex, saltHex, authTagHex) => {
const salt = Buffer.from(saltHex, 'hex');
const iv = Buffer.from(ivHex, 'hex');
const authTag = Buffer.from(authTagHex, 'hex');
const key = getKeyFromPassword(process.env.ENCRYPTION_KEY, salt);
const decipher = crypto.createDecipheriv(algorithm, key, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encryptedContent, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
};

后端业务逻辑与API接口实现

编写主服务器文件server.js,整合数据库连接、加密逻辑和Express路由。我们将提供三个核心接口:创建遗嘱、获取遗嘱列表、解密并查看特定遗嘱。


const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
require('dotenv').config();
const connectDB = require('./db');
const Will = require('./models/Will');
const { encrypt, decrypt } = require('./utils/crypto');
const app = express();
// 中间件配置
app.use(cors());
app.use(bodyParser.json({ limit: '10mb' })); // 允许较大的遗嘱文本
// 1. 创建遗嘱接口
app.post('/api/wills', async (req, res) => {
try {
const { testatorName, content } = req.body;
if (!content || !testatorName) {
return res.status(400).json({ error: 'Missing required fields' });
}
// 生成内容哈希用于后续验证
const contentHash = crypto.createHash('sha256').update(content).digest('hex');
// 加密内容
const encryptedData = encrypt(content);
const newWill = new Will({
testatorName,
encryptedContent: encryptedData.content,
iv: encryptedData.iv,
salt: encryptedData.salt, // 需要在Model中添加salt字段,这里为了演示逻辑
authTag: encryptedData.authTag, // 需要在Model中添加authTag字段
authHash: contentHash
});
// 注意:请确保models/Will.js中包含 salt 和 authTag 字段
// const WillSchema = new mongoose.Schema({ ..., salt: String, authTag: String ... });
await newWill.save();
res.status(201).json({ message: 'Will archived successfully', id: newWill._id });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// 2. 获取遗嘱列表(仅返回元数据,不返回内容)
app.get('/api/wills', async (req, res) => {
try {
const wills = await Will.find({}, 'testatorName createdAt status');
res.json(wills);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// 3. 查看并解密遗嘱
app.get('/api/wills/:id', async (req, res) => {
try {
const will = await Will.findById(req.params.id);
if (!will) return res.status(404).json({ error: 'Will not found' });
// 解密操作
const decryptedContent = decrypt(
will.encryptedContent,
will.iv,
will.salt,
will.authTag
);
// 验证完整性
const currentHash = crypto.createHash('sha256').update(decryptedContent).digest('hex');
if (currentHash !== will.authHash) {
return res.status(500).json({ error: 'Data integrity check failed' });
}
res.json({
testatorName: will.testatorName,
content: decryptedContent,
createdAt: will.createdAt
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// 启动服务
const PORT = process.env.PORT || 3000;
const startServer = async () => {
await connectDB();
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
};
startServer();

重要修正:请在models/Will.js中添加saltauthTag字段,否则上述代码会报错。完整的Schema应包含这两个字段。

前端交互页面构建

为了方便测试,我们在public目录下创建一个简单的HTML页面,通过Fetch API与后端交互。

创建public/index.html






遗嘱数字档案馆系统



遗嘱数字档案馆系统

1. 归档新遗嘱



2. 读取遗嘱

修改server.js,添加静态文件托管支持,以便访问该页面:


app.use(express.static('public'));

系统运行与功能测试

所有代码已准备就绪,现在启动系统并进行全流程测试。

1. 启动服务

在项目根目录下执行:

node server.js

控制台应输出“MongoDB Connected Successfully”和“Server running on port 3000”。

2. 归档测试

  1. 打开浏览器访问 http://localhost:3000
  2. 在“归档新遗嘱”区域,输入姓名和一段敏感的遗嘱文本。
  3. 点击“加密并归档”按钮。
  4. 观察返回的JSON结果,记录下返回的_id(例如:65f1a2b3c4d5e6f7g8h9i0j1)。

3. 存储验证

打开MongoDB Compass或使用命令行连接数据库,查看will_db数据库中的wills集合。你会发现encryptedContent字段是一串乱码,证明明文未直接存储。

4. 解密测试

  1. 将步骤2中获取的ID填入“读取遗嘱”输入框。
  2. 点击“解密并查看”。
  3. 页面下方将显示解密后的原始遗嘱内容和立遗嘱人姓名,证明加密解密流程闭环成功。

5. 完整性破坏测试(进阶)

为了验证安全性,可以直接在数据库中修改某条记录的encryptedContent的一个字符,然后再次执行读取操作。系统应返回“Data integrity check failed”或抛出解密错误,这是因为AES-GCM的AuthTag校验失败,确保了数据不可篡改。

AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

扫码咨询
安答联动微信公众号二维码

微信扫码关注安答联动

申请试用
热线电话
申请试用

安答联动档案管理系统