71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
import { Router } from 'express';
|
|
import bcrypt from 'bcrypt';
|
|
import jwt from 'jsonwebtoken';
|
|
import { prisma } from '../lib/prisma';
|
|
import { authenticate } from '../middleware/auth';
|
|
import { AppError } from '../middleware/errorHandler';
|
|
|
|
const router = Router();
|
|
|
|
// POST /api/auth/login
|
|
router.post('/login', async (req, res, next) => {
|
|
try {
|
|
const { email, password } = req.body as { email: string; password: string };
|
|
|
|
if (!email || !password) {
|
|
throw new AppError(400, '이메일과 비밀번호를 입력해주세요.');
|
|
}
|
|
|
|
const user = await prisma.user.findUnique({ where: { email } });
|
|
if (!user || !user.isActive) {
|
|
throw new AppError(401, '이메일 또는 비밀번호가 올바르지 않습니다.');
|
|
}
|
|
|
|
const isMatch = await bcrypt.compare(password, user.password);
|
|
if (!isMatch) {
|
|
throw new AppError(401, '이메일 또는 비밀번호가 올바르지 않습니다.');
|
|
}
|
|
|
|
const token = jwt.sign(
|
|
{ userId: user.id, email: user.email, role: user.role },
|
|
process.env.JWT_SECRET!,
|
|
{ expiresIn: process.env.JWT_EXPIRES_IN || '7d' } as jwt.SignOptions,
|
|
);
|
|
|
|
res.json({
|
|
token,
|
|
user: {
|
|
id: user.id,
|
|
email: user.email,
|
|
name: user.name,
|
|
role: user.role,
|
|
department: user.department,
|
|
},
|
|
});
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
// GET /api/auth/me
|
|
router.get('/me', authenticate, async (req, res, next) => {
|
|
try {
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: req.user!.userId },
|
|
select: { id: true, email: true, name: true, role: true, department: true },
|
|
});
|
|
|
|
if (!user) throw new AppError(404, '사용자를 찾을 수 없습니다.');
|
|
res.json(user);
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
// POST /api/auth/logout (클라이언트 토큰 삭제용 — 서버는 stateless)
|
|
router.post('/logout', authenticate, (_req, res) => {
|
|
res.json({ message: '로그아웃 되었습니다.' });
|
|
});
|
|
|
|
export default router;
|