import express from 'express'; import User from '../models/User.js'; import AuditLog from '../models/AuditLog.js'; import { asyncHandler } from '../middleware/errorHandler.js'; import { requireAuth } from '../middleware/auth.js'; const router = express.Router(); /** * POST /api/auth/login * 使用者登入 */ router.post('/login', asyncHandler(async (req, res) => { const { identifier, password } = req.body; // identifier 可以是 email 或 employee_id // 驗證輸入 if (!identifier || !password) { return res.status(400).json({ success: false, error: '請提供帳號和密碼' }); } try { // 查找使用者(支援 email 或工號登入) let user = null; if (identifier.includes('@')) { user = await User.findByEmail(identifier); } else { user = await User.findByEmployeeId(identifier); } if (!user) { // 記錄失敗的登入嘗試 await AuditLog.create({ action: 'login_failed', ip_address: req.ip, user_agent: req.get('user-agent'), status: 'failed', error_message: `Login failed for: ${identifier}` }); return res.status(401).json({ success: false, error: '帳號或密碼錯誤' }); } // 驗證密碼 const isValid = await User.verifyPassword(password, user.password_hash); if (!isValid) { await AuditLog.logLogin(user.id, req.ip, req.get('user-agent'), false); return res.status(401).json({ success: false, error: '帳號或密碼錯誤' }); } // 建立 Session req.session.userId = user.id; req.session.userRole = user.role; req.session.username = user.username; // 更新最後登入時間 await User.updateLastLogin(user.id); // 記錄成功登入 await AuditLog.logLogin(user.id, req.ip, req.get('user-agent'), true); // 返回使用者資訊(不含密碼) const { password_hash, ...userInfo } = user; res.json({ success: true, message: '登入成功', user: userInfo }); } catch (error) { console.error('Login error:', error); res.status(500).json({ success: false, error: '登入失敗', message: error.message }); } })); /** * POST /api/auth/logout * 使用者登出 */ router.post('/logout', requireAuth, asyncHandler(async (req, res) => { const userId = req.session.userId; // 記錄登出 await AuditLog.logLogout(userId, req.ip, req.get('user-agent')); // 銷毀 Session req.session.destroy((err) => { if (err) { console.error('Session destroy error:', err); return res.status(500).json({ success: false, error: '登出失敗' }); } res.json({ success: true, message: '已登出' }); }); })); /** * GET /api/auth/me * 取得當前使用者資訊 */ router.get('/me', requireAuth, asyncHandler(async (req, res) => { const user = await User.findById(req.session.userId); if (!user) { return res.status(404).json({ success: false, error: '使用者不存在' }); } res.json({ success: true, user: user }); })); /** * POST /api/auth/change-password * 修改密碼 */ router.post('/change-password', requireAuth, asyncHandler(async (req, res) => { const { currentPassword, newPassword } = req.body; const userId = req.session.userId; if (!currentPassword || !newPassword) { return res.status(400).json({ success: false, error: '請提供當前密碼和新密碼' }); } // 驗證新密碼強度 if (newPassword.length < 8) { return res.status(400).json({ success: false, error: '新密碼長度至少 8 個字元' }); } // 取得使用者(含密碼) const user = await User.findByEmail((await User.findById(userId)).email); // 驗證當前密碼 const isValid = await User.verifyPassword(currentPassword, user.password_hash); if (!isValid) { return res.status(401).json({ success: false, error: '當前密碼錯誤' }); } // 更新密碼 await User.updatePassword(userId, newPassword); // 記錄密碼變更 await AuditLog.create({ user_id: userId, action: 'change_password', ip_address: req.ip, user_agent: req.get('user-agent') }); res.json({ success: true, message: '密碼已更新' }); })); export default router;