备份:修复前完整项目快照 2026-04-19

This commit is contained in:
root
2026-04-19 19:15:01 +08:00
parent 5266d7732b
commit d00f41a120
449 changed files with 89577 additions and 23251 deletions
+74
View File
@@ -0,0 +1,74 @@
// 认证工具函数
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
// JWT 密钥(生产环境应从环境变量读取)
const JWT_SECRET = process.env.JWT_SECRET || 'your-jwt-secret-change-in-production';
const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '24h';
/**
* 密码哈希
* @param {string} password - 明文密码
* @returns {string} - 哈希后的密码
*/
function hashPassword(password) {
const saltRounds = 12; // 推荐值:10-14
return bcrypt.hashSync(password, saltRounds);
}
/**
* 验证密码
* @param {string} password - 明文密码
* @param {string} hash - 数据库中的哈希密码
* @returns {boolean} - 是否匹配
*/
function verifyPassword(password, hash) {
return bcrypt.compareSync(password, hash);
}
/**
* 生成 JWT Token
* @param {object} payload - token 载荷 { id, username, role }
* @returns {string} - JWT token
*/
function generateToken(payload) {
return jwt.sign(payload, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN,
issuer: 'company-finance-system',
audience: 'company-finance-client'
});
}
/**
* 验证 JWT Token
* @param {string} token - JWT token
* @returns {object|null} - 解码后的 payload 或 null
*/
function verifyToken(token) {
try {
return jwt.verify(token, JWT_SECRET);
} catch (error) {
return null;
}
}
/**
* 从请求头中提取 token
* @param {object} req - Express 请求对象
* @returns {string|null} - token 或 null
*/
function extractToken(req) {
const authHeader = req.headers.authorization;
if (authHeader && authHeader.startsWith('Bearer ')) {
return authHeader.substring(7);
}
return null;
}
module.exports = {
hashPassword,
verifyPassword,
generateToken,
verifyToken,
extractToken
};
+16
View File
@@ -0,0 +1,16 @@
const { body, validationResult } = require('express-validator');
const validate = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
errors: errors.array()
});
}
next();
};
module.exports = {
validate
};