fix: SSO Auth CORS 정책 강화 및 Redis 세션 지원 추가

- CORS origin 검증 로직 추가 (운영 도메인 + localhost + 192.168.x.x)
- Redis 기반 세션/토큰 관리 유틸 추가
- departments 테이블 JOIN 지원 (findByUsername, findById)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-06 23:17:42 +09:00
parent b3012b8320
commit cad662473b
5 changed files with 1366 additions and 3 deletions

View File

@@ -6,12 +6,16 @@
const jwt = require('jsonwebtoken');
const userModel = require('../models/userModel');
const redis = require('../utils/redis');
const JWT_SECRET = process.env.SSO_JWT_SECRET;
const JWT_EXPIRES_IN = process.env.SSO_JWT_EXPIRES_IN || '7d';
const JWT_REFRESH_SECRET = process.env.SSO_JWT_REFRESH_SECRET;
const JWT_REFRESH_EXPIRES_IN = process.env.SSO_JWT_REFRESH_EXPIRES_IN || '30d';
const MAX_LOGIN_ATTEMPTS = 5;
const LOGIN_LOCKOUT_SECONDS = 300; // 5분
/**
* JWT 토큰 페이로드 생성 (모든 시스템 공통 구조)
*/
@@ -47,16 +51,29 @@ async function login(req, res, next) {
return res.status(400).json({ success: false, error: '사용자명과 비밀번호를 입력하세요' });
}
// 로그인 시도 횟수 확인
const attemptKey = `login_attempts:${username}`;
const attempts = parseInt(await redis.get(attemptKey)) || 0;
if (attempts >= MAX_LOGIN_ATTEMPTS) {
return res.status(429).json({ success: false, error: '로그인 시도 횟수를 초과했습니다. 5분 후 다시 시도하세요' });
}
const user = await userModel.findByUsername(username);
if (!user) {
await redis.incr(attemptKey);
await redis.expire(attemptKey, LOGIN_LOCKOUT_SECONDS);
return res.status(401).json({ success: false, error: '사용자명 또는 비밀번호가 올바르지 않습니다' });
}
const valid = await userModel.verifyPassword(password, user.password_hash);
if (!valid) {
await redis.incr(attemptKey);
await redis.expire(attemptKey, LOGIN_LOCKOUT_SECONDS);
return res.status(401).json({ success: false, error: '사용자명 또는 비밀번호가 올바르지 않습니다' });
}
// 로그인 성공 시 시도 횟수 초기화
await redis.del(attemptKey);
await userModel.updateLastLogin(user.user_id);
const payload = createTokenPayload(user);