- 관리자 로그인 시스템 (JWT, 30일 만료) - admin_users 테이블 및 bcrypt 암호화 - 로그인 페이지 (/admin) - 대시보드 (/admin/dashboard) - 메뉴: 멤버, 앨범, 일정 관리
123 lines
3.2 KiB
JavaScript
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;
|