fix: 系统检查修复 — 安全和稳定性
后端: - config.ts 使用 requireAdmin 中间件,统一响应格式 - feedback.ts 使用 requireAdmin 中间件,移除重复权限检查 - feedback.ts 添加 affectedRows 检查(反馈不存在时返回 404) - 全局错误处理中间件兜底未捕获异常 前端: - request.ts 添加 15 秒请求超时设置
This commit is contained in:
@@ -47,6 +47,7 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
|
|||||||
url: API_BASE + options.url,
|
url: API_BASE + options.url,
|
||||||
method: options.method || 'GET',
|
method: options.method || 'GET',
|
||||||
data: options.data,
|
data: options.data,
|
||||||
|
timeout: 15000, // 15秒超时
|
||||||
header: {
|
header: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
...(token ? { Authorization: `Bearer ${token}` } : {})
|
...(token ? { Authorization: `Bearer ${token}` } : {})
|
||||||
|
|||||||
@@ -171,6 +171,12 @@ app.get('/api/health', async (_req, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 全局错误处理中间件(兜底未捕获的异常)
|
||||||
|
app.use((err: any, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
|
||||||
|
console.error('[Global] Unhandled error:', err)
|
||||||
|
res.status(500).json({ code: 50000, message: '服务器内部错误' })
|
||||||
|
})
|
||||||
|
|
||||||
let server: any
|
let server: any
|
||||||
|
|
||||||
// 生产环境:先备份再迁移,迁移出问题可恢复
|
// 生产环境:先备份再迁移,迁移出问题可恢复
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Router } from 'express'
|
import { Router } from 'express'
|
||||||
import pool from '../db/connection'
|
import pool from '../db/connection'
|
||||||
import { authMiddleware } from '../middleware/auth'
|
import { requireAdmin } from '../middleware/requireAdmin'
|
||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
/** 获取公开配置(无需管理员权限) */
|
/** 获取公开配置(经过全局 authMiddleware,无需管理员权限) */
|
||||||
router.get('/', async (_req, res) => {
|
router.get('/', async (_req, res) => {
|
||||||
try {
|
try {
|
||||||
const [rows] = await pool.execute('SELECT config_key, config_value FROM sys_config')
|
const [rows] = await pool.execute('SELECT config_key, config_value FROM sys_config')
|
||||||
@@ -20,19 +20,11 @@ router.get('/', async (_req, res) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** 更新配置(管理员权限) */
|
/** 更新配置(管理员权限) */
|
||||||
router.put('/', authMiddleware, async (req, res) => {
|
router.put('/', requireAdmin, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const userId = (req as any).userId
|
|
||||||
const [users] = await pool.execute('SELECT role FROM users WHERE id = ?', [userId])
|
|
||||||
const user = (users as any[])[0]
|
|
||||||
|
|
||||||
if (!user || user.role !== 'admin') {
|
|
||||||
return res.status(403).json({ error: '无权限' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = req.body
|
const data = req.body
|
||||||
if (!data || typeof data !== 'object') {
|
if (!data || typeof data !== 'object') {
|
||||||
return res.status(400).json({ error: '无效的配置数据' })
|
return res.status(400).json({ code: 40001, message: '无效的配置数据' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量更新配置
|
// 批量更新配置
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Router } from 'express'
|
import { Router } from 'express'
|
||||||
import pool from '../db/connection'
|
import pool from '../db/connection'
|
||||||
import { authMiddleware } from '../middleware/auth'
|
import { authMiddleware } from '../middleware/auth'
|
||||||
|
import { requireAdmin } from '../middleware/requireAdmin'
|
||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
@@ -30,16 +31,8 @@ router.post('/', authMiddleware, async (req, res) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** 管理员获取反馈列表 */
|
/** 管理员获取反馈列表 */
|
||||||
router.get('/', authMiddleware, async (req, res) => {
|
router.get('/', requireAdmin, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const userId = (req as any).userId
|
|
||||||
const [users] = await pool.execute('SELECT role FROM users WHERE id = ?', [userId])
|
|
||||||
const user = (users as any[])[0]
|
|
||||||
|
|
||||||
if (!user || user.role !== 'admin') {
|
|
||||||
return res.status(403).json({ code: 40300, message: '无权限' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const page = Math.max(1, parseInt(req.query.page as string) || 1)
|
const page = Math.max(1, parseInt(req.query.page as string) || 1)
|
||||||
const pageSize = Math.min(100, Math.max(1, parseInt(req.query.pageSize as string) || 20))
|
const pageSize = Math.min(100, Math.max(1, parseInt(req.query.pageSize as string) || 20))
|
||||||
const status = req.query.status as string
|
const status = req.query.status as string
|
||||||
@@ -77,16 +70,8 @@ router.get('/', authMiddleware, async (req, res) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** 管理员更新反馈状态 */
|
/** 管理员更新反馈状态 */
|
||||||
router.put('/:id/status', authMiddleware, async (req, res) => {
|
router.put('/:id/status', requireAdmin, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const userId = (req as any).userId
|
|
||||||
const [users] = await pool.execute('SELECT role FROM users WHERE id = ?', [userId])
|
|
||||||
const user = (users as any[])[0]
|
|
||||||
|
|
||||||
if (!user || user.role !== 'admin') {
|
|
||||||
return res.status(403).json({ code: 40300, message: '无权限' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id } = req.params
|
const { id } = req.params
|
||||||
const { status, admin_reply } = req.body
|
const { status, admin_reply } = req.body
|
||||||
|
|
||||||
@@ -102,6 +87,10 @@ router.put('/:id/status', authMiddleware, async (req, res) => {
|
|||||||
)
|
)
|
||||||
const feedback = (feedbackRows as any[])[0]
|
const feedback = (feedbackRows as any[])[0]
|
||||||
|
|
||||||
|
if (!feedback) {
|
||||||
|
return res.status(404).json({ code: 40400, message: '反馈不存在' })
|
||||||
|
}
|
||||||
|
|
||||||
await pool.execute(
|
await pool.execute(
|
||||||
'UPDATE feedbacks SET status = ?, admin_reply = ? WHERE id = ?',
|
'UPDATE feedbacks SET status = ?, admin_reply = ? WHERE id = ?',
|
||||||
[status, admin_reply || '', id]
|
[status, admin_reply || '', id]
|
||||||
|
|||||||
Reference in New Issue
Block a user