Phase 1: notifyHelper.js → shared/utils/ (4개 서비스 중복 제거) Phase 2: auth.js → shared/middleware/ (system1/system2 통합) Phase 3: errors.js + logger.js → shared/utils/ (system1/system2 통합) Phase 4: DB pool → shared/config/database.js (Group B 4개 서비스 통합) - Docker 빌드 컨텍스트를 루트로 변경 (6개 API 서비스) - 기존 파일은 re-export 패턴으로 consumer 변경 0개 유지 - .dockerignore 추가로 빌드 최적화 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
82 lines
2.8 KiB
JavaScript
82 lines
2.8 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();
|
|
// 1. 개인 권한
|
|
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: '접근 권한이 없습니다' });
|
|
}
|
|
// 2. 부서 권한
|
|
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: '접근 권한이 없습니다' });
|
|
}
|
|
}
|
|
// 3. 기본 거부
|
|
return res.status(403).json({ success: false, error: '접근 권한이 없습니다' });
|
|
} catch (err) {
|
|
console.error('Permission check error:', err);
|
|
return res.status(500).json({ success: false, error: '권한 확인 실패' });
|
|
}
|
|
};
|
|
}
|
|
|
|
module.exports = { getPool, extractToken, requireAuth, requireAdmin, requirePage };
|