fromis_9/backend/routes/admin.js
caadiq 009c428d37 feat: 관리자 페이지 추가
- 관리자 로그인 시스템 (JWT, 30일 만료)
- admin_users 테이블 및 bcrypt 암호화
- 로그인 페이지 (/admin)
- 대시보드 (/admin/dashboard)
- 메뉴: 멤버, 앨범, 일정 관리
2026-01-01 18:01:42 +09:00

123 lines
3.2 KiB
JavaScript

import express from "express";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import pool from "../lib/db.js";
const router = express.Router();
// JWT 비밀키 (실제 운영에서는 환경변수로 관리)
const JWT_SECRET = process.env.JWT_SECRET || "fromis9-admin-secret-key-2026";
const JWT_EXPIRES_IN = "30d"; // 30일
// 관리자 로그인
router.post("/login", async (req, res) => {
try {
const { username, password } = req.body;
if (!username || !password) {
return res
.status(400)
.json({ error: "아이디와 비밀번호를 입력해주세요." });
}
// 사용자 조회
const [users] = await pool.query(
"SELECT * FROM admin_users WHERE username = ?",
[username]
);
if (users.length === 0) {
return res
.status(401)
.json({ error: "아이디 또는 비밀번호가 올바르지 않습니다." });
}
const user = users[0];
// 비밀번호 검증
const isValidPassword = await bcrypt.compare(password, user.password_hash);
if (!isValidPassword) {
return res
.status(401)
.json({ error: "아이디 또는 비밀번호가 올바르지 않습니다." });
}
// JWT 토큰 발급
const token = jwt.sign(
{ id: user.id, username: user.username },
JWT_SECRET,
{ expiresIn: JWT_EXPIRES_IN }
);
res.json({
message: "로그인 성공",
token,
user: {
id: user.id,
username: user.username,
},
});
} catch (error) {
console.error("로그인 오류:", error);
res.status(500).json({ error: "로그인 처리 중 오류가 발생했습니다." });
}
});
// 토큰 검증 미들웨어
export const authenticateToken = (req, res, next) => {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN
if (!token) {
return res.status(401).json({ error: "인증이 필요합니다." });
}
jwt.verify(token, JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ error: "유효하지 않은 토큰입니다." });
}
req.user = user;
next();
});
};
// 토큰 검증 엔드포인트
router.get("/verify", authenticateToken, (req, res) => {
res.json({
valid: true,
user: req.user,
});
});
// 초기 관리자 계정 생성 (한 번만 실행)
router.post("/init", async (req, res) => {
try {
// 이미 계정이 있는지 확인
const [existing] = await pool.query(
"SELECT COUNT(*) as count FROM admin_users"
);
if (existing[0].count > 0) {
return res.status(400).json({ error: "이미 관리자 계정이 존재합니다." });
}
// 비밀번호 해시 생성
const password = "auddnek0403!";
const saltRounds = 10;
const passwordHash = await bcrypt.hash(password, saltRounds);
// 계정 생성
await pool.query(
"INSERT INTO admin_users (username, password_hash) VALUES (?, ?)",
["admin", passwordHash]
);
res.json({ message: "관리자 계정이 생성되었습니다." });
} catch (error) {
console.error("계정 생성 오류:", error);
res.status(500).json({ error: "계정 생성 중 오류가 발생했습니다." });
}
});
export default router;