开发一个支持加密访问文档的网页版应用程序涉及多个步骤,包括用户认证、文档加密和解密、文件上传和下载,以及确保整个过程中的数据安全性。下面是一个详细的步骤指南:
步骤1:设置项目环境
首先,设置一个新的项目环境。假设你使用的是Node.js和React.js进行前后端开发。
-
初始化项目:
npx create-react-app encrypted-docs-app cd encrypted-docs-app npm init -y
-
安装必要的依赖:
npm install express mongoose bcryptjs jsonwebtoken dotenv multer crypto-js npm install --save-dev nodemon
步骤2:设置后端(Node.js + Express)
-
创建服务器文件:
在项目根目录下创建server.js
文件。const express = require('express'); const mongoose = require('mongoose'); const dotenv = require('dotenv'); const cors = require('cors'); const authRoutes = require('./routes/auth'); const docRoutes = require('./routes/docs');dotenv.config(); const app = express();app.use(cors()); app.use(express.json());mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });app.use('/api/auth', authRoutes); app.use('/api/docs', docRoutes);const PORT = process.env.PORT || 5000; app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
-
用户认证:
创建一个新的目录routes
,并在其中创建auth.js
文件。const express = require('express'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const User = require('../models/User');const router = express.Router();// 注册 router.post('/register', async (req, res) => {const { username, password } = req.body;const salt = await bcrypt.genSalt(10);const hashedPassword = await bcrypt.hash(password, salt);const newUser = new User({ username, password: hashedPassword });try {const savedUser = await newUser.save();res.status(201).json(savedUser);} catch (err) {res.status(400).json(err);} });// 登录 router.post('/login', async (req, res) => {const { username, password } = req.body;try {const user = await User.findOne({ username });if (!user) return res.status(400).json({ message: "User not found" });const isMatch = await bcrypt.compare(password, user.password);if (!isMatch) return res.status(400).json({ message: "Invalid credentials" });const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });res.status(200).json({ token });} catch (err) {res.status(500).json(err);} });module.exports = router;
-
文档上传和下载:
在routes
目录下创建docs.js
文件。const express = require('express'); const multer = require('multer'); const jwt = require('jsonwebtoken'); const fs = require('fs'); const crypto = require('crypto'); const path = require('path');const router = express.Router();const storage = multer.diskStorage({destination: (req, file, cb) => {cb(null, 'uploads/');},filename: (req, file, cb) => {cb(null, `${file.fieldname}-${Date.now()}${path.extname(file.originalname)}`);} });const upload = multer({ storage });// 中间件验证JWT const verifyToken = (req, res, next) => {const token = req.header('x-auth-token');if (!token) return res.status(401).json({ message: 'No token, authorization denied' });try {const decoded = jwt.verify(token, process.env.JWT_SECRET);req.user = decoded;next();} catch (err) {res.status(400).json({ message: 'Token is not valid' });} };// 文件加密 const encryptFile = (filePath) => {const cipher = crypto.createCipher('aes-256-ctr', process.env.ENCRYPTION_SECRET);const input = fs.createReadStream(filePath);const output = fs.createWriteStream(`${filePath}.enc`);input.pipe(cipher).pipe(output); };// 文件解密 const decryptFile = (filePath, res) => {const decipher = crypto.createDecipher('aes-256-ctr', process.env.ENCRYPTION_SECRET);const input = fs.createReadStream(filePath);const output = res;input.pipe(decipher).pipe(output); };// 上传文档 router.post('/upload', verifyToken, upload.single('document'), (req, res) => {const filePath = req.file.path;encryptFile(filePath);fs.unlinkSync(filePath); // 删除原始文件,保留加密文件res.status(200).json({ message: 'File uploaded and encrypted successfully' }); });// 下载文档 router.get('/download/:filename', verifyToken, (req, res) => {const filePath = `uploads/${req.params.filename}`;decryptFile(filePath, res); });module.exports = router;
-
创建用户模型:
在models
目录下创建User.js
文件。const mongoose = require('mongoose');const UserSchema = new mongoose.Schema({username: { type: String, required: true, unique: true },password: { type: String, required: true }, });module.exports = mongoose.model('User', UserSchema);
步骤3:设置前端(React)
-
创建登录和注册页面:
在src
目录下创建components
目录,并在其中创建Login.js
和Register.js
文件。// src/components/Register.js import React, { useState } from 'react'; import axios from 'axios';const Register = () => {const [username, setUsername] = useState('');const [password, setPassword] = useState('');const handleSubmit = async (e) => {e.preventDefault();try {const res = await axios.post('http://localhost:5000/api/auth/register', { username, password });console.log(res.data);} catch (err) {console.error(err);}};return (<form onSubmit={handleSubmit}><input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="Username" /><input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" /><button type="submit">Register</button></form>); };export default Register;
// src/components/Login.js import React, { useState } from 'react'; import axios from 'axios';const Login = ({ setToken }) => {const [username, setUsername] = useState('');const [password, setPassword] = useState('');const handleSubmit = async (e) => {e.preventDefault();try {const res = await axios.post('http://localhost:5000/api/auth/login', { username, password });setToken(res.data.token);} catch (err) {console.error(err);}};return (<form onSubmit={handleSubmit}><input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="Username" /><input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" /><button type="submit">Login</button></form>); };export default Login;
-
创建文档上传和下载页面:
在src/components
目录下创建Upload.js
和Download.js
文件。// src/components/Upload.js import React, { useState } from 'react'; import axios from 'axios';const Upload = ({ token }) => {const [file, setFile] = useState(null);const handleFileChange = (e) => {setFile(e.target.files[0]);};const handleSubmit = async (e) => {e.preventDefault();const formData = new FormData();formData.append('document', file);try {await axios.post('http://localhost:5000/api/docs/upload', formData, {headers: {'Content-Type': 'multipart/form-data','x-auth-token': token}});alert('File uploaded and encrypted successfully');} catch (err) {console.error(err);}};return (<form onSubmit={handleSubmit}>
export default Upload;
```jsx
// src/components/Download.js
import React, { useState } from 'react';
import axios from 'axios';const Download = ({ token }) => {const [filename, setFilename] = useState('');const handleSubmit = async (e) => {e.preventDefault();try {const res = await axios.get(`http://localhost:5000/api/docs/download/${filename}`, {headers: {'x-auth-token': token},responseType: 'blob'});const url = window.URL.createObjectURL(new Blob([res.data]));const link = document.createElement('a');link.href = url;link.setAttribute('download', filename);document.body.appendChild(link);link.click();} catch (err) {console.error(err);}};return (<form onSubmit={handleSubmit}><input type="text" value={filename} onChange={(e) => setFilename(e.target.value)} placeholder="Filename" /><button type="submit">Download</button></form>);
};export default Download;
-
设置App组件和路由:
修改src/App.js
文件,整合上述组件并设置路由。// src/App.js import React, { useState } from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import Login from './components/Login'; import Register from './components/Register'; import Upload from './components/Upload'; import Download from './components/Download';const App = () => {const [token, setToken] = useState('');return (<Router><div><Switch><Route path="/register"><Register /></Route><Route path="/login"><Login setToken={setToken} /></Route><Route path="/upload"><Upload token={token} /></Route><Route path="/download"><Download token={token} /></Route><Route path="/"><h1>Welcome to Encrypted Docs App</h1></Route></Switch></div></Router>); };export default App;
总结
通过上述步骤,你可以开发一个支持加密访问文档的网页版应用程序。该应用程序包括用户认证、文件上传与下载、文件加密与解密等功能,确保文档的安全性。