diff --git a/.gitignore b/.gitignore index be1c71e..0e9e700 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,8 @@ build/ # Environment variables .env .env.local +.env.production +.env.production.local .env.*.local # IDE diff --git a/backend/.env.production b/backend/.env.production index a27588c..da22eeb 100644 --- a/backend/.env.production +++ b/backend/.env.production @@ -2,16 +2,20 @@ NODE_ENV=production PORT=5000 -# 生产数据库配置 +# 生产数据库配置(请填写实际值,不要提交此文件到版本控制) DB_HOST=localhost DB_PORT=5432 DB_NAME=company_finance_db DB_USER=finance_user -DB_PASSWORD=FinanceDB2026! +DB_PASSWORD= -# 安全配置 -JWT_SECRET=your-production-jwt-secret-key-change-this -SESSION_SECRET=your-production-session-secret-change-this +# 安全配置(请填写实际值) +JWT_SECRET= +SESSION_SECRET= + +# 腾讯云COS配置(请填写实际值) +TENCENT_SECRET_ID= +TENCENT_SECRET_KEY= # 日志配置 LOG_LEVEL=info diff --git a/backend/api-complete.js b/backend/api-complete.js index 4935b23..8557ed5 100644 --- a/backend/api-complete.js +++ b/backend/api-complete.js @@ -5,6 +5,7 @@ const multer = require('multer'); const xlsx = require('xlsx'); require('dotenv').config(); const db = require('./db-sqlite'); +const { verifyPassword, generateToken } = require('./utils/auth'); // 文件上传配置 const storage = multer.memoryStorage(); @@ -15,7 +16,13 @@ const app = express(); const PORT = process.argv[2] || process.env.PORT || 3000; // 中间件 -app.use(cors()); +const corsOptions = { + origin: process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : ['http://localhost:5173', 'http://localhost:3001'], + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +}; +app.use(cors(corsOptions)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); @@ -61,17 +68,23 @@ app.post('/api/auth/login', [ try { const { username, password } = req.body; const result = await db.query( - 'SELECT id, username, role, name FROM users WHERE username = ? AND password = ?', - [username, password] + 'SELECT id, username, role, name, password_hash FROM users WHERE username = ?', + [username] ); if (result.rows.length === 0) { return res.status(401).json({ success: false, message: '用户名或密码错误' }); } - res.json({ success: true, data: result.rows[0] }); + const user = result.rows[0]; + if (!user.password_hash || !verifyPassword(password, user.password_hash)) { + return res.status(401).json({ success: false, message: '用户名或密码错误' }); + } + + const token = generateToken({ id: user.id, username: user.username, role: user.role }); + res.json({ success: true, data: { id: user.id, username: user.username, role: user.role, name: user.name, token } }); } catch (error) { - res.status(500).json({ success: false, message: error.message }); + res.status(500).json({ success: false, message: '登录失败' }); } }); @@ -81,28 +94,26 @@ app.post('/api/users/login', [ body('password').notEmpty() ], validate, async (req, res) => { try { - console.log('收到登录请求:', req.body); const { username, password } = req.body; const result = await db.query( - 'SELECT id, username, role, name FROM users WHERE username = ? AND password = ?', - [username, password] + 'SELECT id, username, role, name, password_hash FROM users WHERE username = ?', + [username] ); - console.log('查询结果:', result.rows); - if (result.rows.length === 0) { - console.log('登录失败: 用户不存在或密码错误'); return res.status(401).json({ user: null, token: null, message: '用户名或密码错误' }); } - // 返回前端期望的格式 - const responseData = { user: result.rows[0], token: 'dummy-token-' + Date.now() }; - console.log('登录成功,返回数据:', responseData); - res.json(responseData); + const user = result.rows[0]; + if (!user.password_hash || !verifyPassword(password, user.password_hash)) { + return res.status(401).json({ user: null, token: null, message: '用户名或密码错误' }); + } + + const token = generateToken({ id: user.id, username: user.username, role: user.role }); + res.json({ user: { id: user.id, username: user.username, role: user.role, name: user.name }, token }); } catch (error) { - console.error('登录错误:', error); - res.status(500).json({ user: null, token: null, message: error.message }); + res.status(500).json({ user: null, token: null, message: '登录失败' }); } }); diff --git a/backend/app-simple.js b/backend/app-simple.js index dfb353d..9b2c8b6 100644 --- a/backend/app-simple.js +++ b/backend/app-simple.js @@ -9,7 +9,13 @@ const app = express(); const PORT = process.env.PORT || 3002; // 中间件 -app.use(cors()); +const corsOptions = { + origin: process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : ['http://localhost:5173', 'http://localhost:3001'], + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +}; +app.use(cors(corsOptions)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); diff --git a/backend/app.js b/backend/app.js index 6d64c30..8020cc5 100644 --- a/backend/app.js +++ b/backend/app.js @@ -9,7 +9,13 @@ const app = express(); const PORT = process.env.PORT || 3002; // 中间件 -app.use(cors()); +const corsOptions = { + origin: process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : ['http://localhost:5173', 'http://localhost:3001'], + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +}; +app.use(cors(corsOptions)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); diff --git a/backend/app_fixed.js b/backend/app_fixed.js index 47c33b9..050bdd3 100644 --- a/backend/app_fixed.js +++ b/backend/app_fixed.js @@ -9,7 +9,13 @@ const app = express(); const PORT = process.env.PORT || 3002; // 中间件 -app.use(cors()); +const corsOptions = { + origin: process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : ['http://localhost:5173', 'http://localhost:3001'], + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +}; +app.use(cors(corsOptions)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); diff --git a/backend/db.js b/backend/db.js index e908e8b..6d851f2 100644 --- a/backend/db.js +++ b/backend/db.js @@ -1,11 +1,12 @@ const { Pool } = require('pg'); +require('dotenv').config(); const pool = new Pool({ - host: 'localhost', - port: 5432, - database: 'company_finance', - user: 'postgres', - password: 'X123c321@', + host: process.env.DB_HOST || 'localhost', + port: parseInt(process.env.DB_PORT || '5432'), + database: process.env.DB_NAME || 'company_finance', + user: process.env.DB_USER || 'postgres', + password: process.env.DB_PASSWORD, max: 20, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, diff --git a/backend/ecosystem.config.js b/backend/ecosystem.config.js index 601bf6c..0d8bfa3 100644 --- a/backend/ecosystem.config.js +++ b/backend/ecosystem.config.js @@ -17,7 +17,7 @@ module.exports = { DB_PORT: 5432, DB_NAME: 'company_finance_db', DB_USER: 'finance_user', - DB_PASSWORD: 'FinanceDB2026!' + DB_PASSWORD: process.env.DB_PASSWORD || '' } }] }; \ No newline at end of file diff --git a/backend/final-backend.js b/backend/final-backend.js index 5a5e370..ebd33b9 100644 --- a/backend/final-backend.js +++ b/backend/final-backend.js @@ -29,7 +29,13 @@ const app = express(); const PORT = process.env.PORT || 3002; // 中间件 -app.use(cors()); +const corsOptions = { + origin: process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : ['http://localhost:5173', 'http://localhost:3001'], + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +}; +app.use(cors(corsOptions)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); @@ -38,21 +44,21 @@ app.use(express.static(path.join(__dirname, '../frontend/dist'))); // 用户相关 API // 获取用户列表 - -// ==================== 认证路由 ==================== -const authRoutes = require('./routes/auth'); -app.use('/api/auth', authRoutes); - - -// ==================== 用户路由 ==================== -const usersRoutes = require('./routes/users'); -app.use('/api/users', usersRoutes); - - -// ==================== 商品路由 ==================== -const productsRoutes = require('./routes/products'); -app.use('/api/products', productsRoutes); - + +// ==================== 认证路由 ==================== +const authRoutes = require('./routes/auth'); +app.use('/api/auth', authRoutes); + + +// ==================== 用户路由 ==================== +const usersRoutes = require('./routes/users'); +app.use('/api/users', usersRoutes); + + +// ==================== 商品路由 ==================== +const productsRoutes = require('./routes/products'); +app.use('/api/products', productsRoutes); + // 创建供应商收款信息表 async function createSupplierPaymentInfosTable() { diff --git a/backend/middleware/auth.js b/backend/middleware/auth.js index fa34b40..85db0f4 100644 --- a/backend/middleware/auth.js +++ b/backend/middleware/auth.js @@ -1,7 +1,7 @@ const jwt = require('jsonwebtoken'); const { hashPassword, verifyPassword, verifyToken } = require('../utils/auth'); -const JWT_SECRET = process.env.JWT_SECRET || 'your-jwt-secret-change-in-production'; +const JWT_SECRET = process.env.JWT_SECRET; const generateToken = (user) => { const payload = { diff --git a/backend/production-server.js b/backend/production-server.js index a8c7a33..a279eb7 100644 --- a/backend/production-server.js +++ b/backend/production-server.js @@ -10,7 +10,13 @@ const app = express(); const PORT = process.env.PORT || 5000; // 中间件 -app.use(cors()); +const corsOptions = { + origin: process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : ['http://localhost:5173', 'http://localhost:3001'], + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +}; +app.use(cors(corsOptions)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); diff --git a/backend/server-complete.js b/backend/server-complete.js index e6acb11..7cbebe9 100644 --- a/backend/server-complete.js +++ b/backend/server-complete.js @@ -9,7 +9,13 @@ const app = express(); const PORT = process.env.PORT || 3002; // 中间件 -app.use(cors()); +const corsOptions = { + origin: process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : ['http://localhost:5173', 'http://localhost:3001'], + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +}; +app.use(cors(corsOptions)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); diff --git a/backend/utils/auth.js b/backend/utils/auth.js index 6cd04ac..5618d84 100644 --- a/backend/utils/auth.js +++ b/backend/utils/auth.js @@ -2,10 +2,14 @@ const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); -// JWT 密钥(生产环境应从环境变量读取) -const JWT_SECRET = process.env.JWT_SECRET || 'your-jwt-secret-change-in-production'; +// JWT 密钥 - 必须通过环境变量设置,不提供默认值 +const JWT_SECRET = process.env.JWT_SECRET; const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '24h'; +if (!JWT_SECRET) { + console.error('⚠️ 警告:未设置 JWT_SECRET 环境变量,请在 .env 文件中配置'); +} + /** * 密码哈希 * @param {string} password - 明文密码 diff --git a/codingplan-config.json b/codingplan-config.json index 6ce54f4..ef69d28 100644 --- a/codingplan-config.json +++ b/codingplan-config.json @@ -3,7 +3,7 @@ { "id": "codingplan", "name": "腾讯云CodingPlan", - "apiKey": "sk-sp-xGrYANrlwJfsQ8hAoyR2eUlHntiXlpuPZkFPeddakTXEUwDe", + "apiKey": "", "enabled": true, "models": [ {