- 전사 휴가 부여/관리 (company-holidays) CRUD + 연차차감 트랜잭션 - 전체 휴가관리 대시보드 (vacation-dashboard) 부서별/직원별 현황 - 내 휴가 현황 개선 (/my-status) balance_type별 카드, 전사 휴가일 - requireSupportTeam 미들웨어, 부서명 JOIN, 마이그레이션 002 추가 - 사이드바 roles 기반 메뉴 필터링 (하위호환 유지) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
96 lines
3.4 KiB
JavaScript
96 lines
3.4 KiB
JavaScript
const jwt = require('jsonwebtoken');
|
|
const { getPool } = require('../shared/config/database');
|
|
|
|
const JWT_SECRET = process.env.SSO_JWT_SECRET;
|
|
|
|
function extractToken(req) {
|
|
const authHeader = req.headers['authorization'];
|
|
if (authHeader && authHeader.startsWith('Bearer ')) {
|
|
return authHeader.split(' ')[1];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function requireAuth(req, res, next) {
|
|
const token = extractToken(req);
|
|
if (!token) {
|
|
return res.status(401).json({ success: false, error: '인증이 필요합니다' });
|
|
}
|
|
try {
|
|
const decoded = jwt.verify(token, JWT_SECRET);
|
|
req.user = decoded;
|
|
next();
|
|
} catch {
|
|
return res.status(401).json({ success: false, error: '유효하지 않은 토큰입니다' });
|
|
}
|
|
}
|
|
|
|
function requireAdmin(req, res, next) {
|
|
const token = extractToken(req);
|
|
if (!token) {
|
|
return res.status(401).json({ success: false, error: '인증이 필요합니다' });
|
|
}
|
|
try {
|
|
const decoded = jwt.verify(token, JWT_SECRET);
|
|
if (!['admin', 'system'].includes((decoded.role || '').toLowerCase())) {
|
|
return res.status(403).json({ success: false, error: '관리자 권한이 필요합니다' });
|
|
}
|
|
req.user = decoded;
|
|
next();
|
|
} catch {
|
|
return res.status(401).json({ success: false, error: '유효하지 않은 토큰입니다' });
|
|
}
|
|
}
|
|
|
|
function requirePage(pageName) {
|
|
return async (req, res, next) => {
|
|
const userId = req.user.user_id || req.user.id;
|
|
const role = (req.user.role || '').toLowerCase();
|
|
if (role === 'admin' || role === 'system') return next();
|
|
|
|
try {
|
|
const db = getPool();
|
|
const [rows] = await db.query(
|
|
'SELECT can_access FROM user_page_permissions WHERE user_id = ? AND page_name = ?',
|
|
[userId, pageName]
|
|
);
|
|
if (rows.length > 0) {
|
|
return rows[0].can_access ? next() : res.status(403).json({ success: false, error: '접근 권한이 없습니다' });
|
|
}
|
|
const [userRows] = await db.query('SELECT department_id FROM sso_users WHERE user_id = ?', [userId]);
|
|
if (userRows.length > 0 && userRows[0].department_id) {
|
|
const [deptRows] = await db.query(
|
|
'SELECT can_access FROM department_page_permissions WHERE department_id = ? AND page_name = ?',
|
|
[userRows[0].department_id, pageName]
|
|
);
|
|
if (deptRows.length > 0) {
|
|
return deptRows[0].can_access ? next() : res.status(403).json({ success: false, error: '접근 권한이 없습니다' });
|
|
}
|
|
}
|
|
return res.status(403).json({ success: false, error: '접근 권한이 없습니다' });
|
|
} catch (err) {
|
|
console.error('Permission check error:', err);
|
|
return res.status(500).json({ success: false, error: '권한 확인 실패' });
|
|
}
|
|
};
|
|
}
|
|
|
|
function requireSupportTeam(req, res, next) {
|
|
const token = extractToken(req);
|
|
if (!token) {
|
|
return res.status(401).json({ success: false, error: '인증이 필요합니다' });
|
|
}
|
|
try {
|
|
const decoded = jwt.verify(token, JWT_SECRET);
|
|
if (!['support_team', 'admin', 'system'].includes((decoded.role || '').toLowerCase())) {
|
|
return res.status(403).json({ success: false, error: '지원팀 이상 권한이 필요합니다' });
|
|
}
|
|
req.user = decoded;
|
|
next();
|
|
} catch {
|
|
return res.status(401).json({ success: false, error: '유효하지 않은 토큰입니다' });
|
|
}
|
|
}
|
|
|
|
module.exports = { getPool, extractToken, requireAuth, requireAdmin, requireSupportTeam, requirePage };
|