75 lines
2.1 KiB
TypeScript
75 lines
2.1 KiB
TypeScript
import { Router } from 'express'
|
|
import { requireAuth, requireRole } from '../auth/authMiddleware.js'
|
|
import { insertAuditLog, listAuditLogs } from './auditService.js'
|
|
|
|
const router = Router()
|
|
|
|
// POST /api/audit/log — sendBeacon 수신 (탭 이동 등 클라이언트 감사 로그)
|
|
router.post('/log', requireAuth, async (req, res) => {
|
|
try {
|
|
// sendBeacon은 Content-Type: text/plain으로 전송하므로 body를 직접 파싱
|
|
let body = req.body
|
|
if (typeof body === 'string') {
|
|
try {
|
|
body = JSON.parse(body)
|
|
} catch {
|
|
res.status(400).json({ error: '잘못된 요청 형식입니다.' })
|
|
return
|
|
}
|
|
}
|
|
|
|
const { action, detail } = body as { action?: string; detail?: string }
|
|
|
|
if (!action) {
|
|
res.status(400).json({ error: 'action 필드는 필수입니다.' })
|
|
return
|
|
}
|
|
|
|
const ipAddr = (req.headers['x-forwarded-for'] as string)?.split(',')[0]?.trim() || req.ip || ''
|
|
const userAgent = req.headers['user-agent'] || ''
|
|
|
|
await insertAuditLog({
|
|
userId: req.user!.sub,
|
|
actionCd: action,
|
|
actionDtl: detail,
|
|
ipAddr,
|
|
userAgent,
|
|
})
|
|
|
|
res.json({ success: true })
|
|
} catch (err) {
|
|
console.error('[audit] 감사 로그 기록 오류:', err)
|
|
res.status(500).json({ error: '감사 로그 기록 중 오류가 발생했습니다.' })
|
|
}
|
|
})
|
|
|
|
// GET /api/audit/logs — 관리자용 감사 로그 조회
|
|
router.get('/logs', requireAuth, requireRole('ADMIN'), async (req, res) => {
|
|
try {
|
|
const { page, size, userId, actionCd, from, to } = req.query as {
|
|
page?: string
|
|
size?: string
|
|
userId?: string
|
|
actionCd?: string
|
|
from?: string
|
|
to?: string
|
|
}
|
|
|
|
const result = await listAuditLogs({
|
|
page: page ? parseInt(page, 10) : undefined,
|
|
size: size ? parseInt(size, 10) : undefined,
|
|
userId,
|
|
actionCd,
|
|
from,
|
|
to,
|
|
})
|
|
|
|
res.json(result)
|
|
} catch (err) {
|
|
console.error('[audit] 감사 로그 조회 오류:', err)
|
|
res.status(500).json({ error: '감사 로그 조회 중 오류가 발생했습니다.' })
|
|
}
|
|
})
|
|
|
|
export default router
|