import {} from "../../config";
// Express의 Request 객체를 글로벌 네임스페이스에서 확장
declare global {
namespace Express {
// Express의 Request 인터페이스 확장
export interface Request {
user?: User; // Request 객체에 user 필드 추가 (선택적)
}
}
}
import dotenv from "dotenv";
// 기본적으로 NODE_ENV 환경변수를 'development'로 설정
process.env.NODE_ENV = process.env.NODE_ENV || "development";
// .env 파일에서 환경변수 로드
const envFound = dotenv.config();
// .env 파일을 찾지 못할 경우 에러 발생
if (envFound.error) throw new Error("⚠️ Couldn't find .env file ⚠️");
export default {
port: parseInt(process.env.PORT!, 10), // 서버 포트 번호 (환경변수에서 불러옴)
jwtSecret: process.env.JWT_SECRET!, // JWT 비밀키 (환경변수에서 불러옴)
logs: {
level: process.env.LOG_LEVEL || "silly", // 로깅 레벨 (환경변수에서 불러옴, 기본값 'silly')
},
api: {
prefix: "/api", // API 경로 접두사
},
};
// jsonwebtoken 모듈을 import 합니다.
import jwt from "jsonwebtoken";
// 비밀 키를 설정합니다. 이 키는 토큰을 생성하고 검증할 때 사용됩니다.
const secretKey = "your-secret-key";
// 페이로드를 받아서 JWT 토큰을 생성하는 함수입니다.
export const generateToken = (payload: any): string => {
// jwt.sign 메소드를 사용하여 토큰을 생성합니다.
const token = jwt.sign(payload, secretKey);
// 생성된 토큰을 반환합니다.
return token;
};
// 토큰을 받아서 검증하고, 페이로드를 반환하는 함수입니다.
export const verifyToken = (token: string): any => {
// jwt.verify 메소드를 사용하여 토큰을 검증하고, 페이로드를 디코딩합니다.
const decoded = jwt.verify(token, secretKey);
// 디코딩된 페이로드를 반환합니다.
return decoded;
};
import passport from "passport";
import User from "../models/userModel";
import passportLocal from "passport-local";
import passportJwt from "passport-jwt";
import argon2 from "argon2";
import dotenv from "dotenv";
dotenv.config();
export default () => {
// JWT 전략과 Local 전략을 Passport에 설정
const JwtStrategy = passportJwt.Strategy;
const ExtractJwt = passportJwt.ExtractJwt;
const LocalStrategy = passportLocal.Strategy;
// 로컬 인증 전략 사용 설정
passport.use(
new LocalStrategy(
{
usernameField: "email", // 이메일 필드 명시
passwordField: "password", // 비밀번호 필드 명시
session: false, // 세션 사용 안함
passReqToCallback: true, // 콜백 함수에 req 객체 전달
},
async (req, email, password, done) => {
try {
// 이메일을 사용하여 사용자 검색
const user = await User.findOne({ where: { email } });
if (!user)
return done(null, false, { message: "존재하지 않는 이메일입니다" });
// 비밀번호 검증
if (!(await argon2.verify(user.password, password)))
return done(null, false, { message: "비밀번호가 틀립니다" });
done(null, user); // 검증 성공 시 사용자 정보 전달
} catch (err) {
done(err);
}
}
)
);
// JWT 인증 전략 사용 설정
passport.use(
new JwtStrategy(
{
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // Bearer 토큰으로부터 JWT 추출
secretOrKey: process.env.JWT_SECRET!, // JWT 비밀키
},
async (payload, done) => {
try {
// JWT 페이로드를 사용하여 사용자 검색
const user = await User.findOne({ where: { id: payload.id } });
if (!user) return done(null, false);
done(null, user); // 검증 성공 시 사용자 정보 전달
} catch (err) {
done(err, false);
}
}
)
);
// 세션을 사용할 때만 필요한 코드 (현재 주석 처리됨)
// passport.serializeUser<User, any>((user, done) => {
// done(null, user.email);
// });
// passport.deserializeUser<User, any>(async (email, done) => {
// try {
// const user = await User.findOne({ where: { email } });
// if (!user) return done(new Error('is not exists'));
// done(null, user!);
// } catch (err) {
// done(err);
// }
// });
};
import { Model, DataTypes } from "sequelize";
import { sequelize } from "./sequelize";
// User 모델 클래스 정의
class User extends Model {
public readonly id!: number; // 사용자 ID (자동 생성)
public email!: string; // 사용자 이메일
public password!: string; // 사용자 비밀번호
public name!: string; // 사용자 이름
public nickname!: string; // 사용자 닉네임
public phone?: string; // 사용자 전화번호 (선택적)
// createdAt과 updatedAt은 Sequelize에서 자동으로 관리됨
}
// User 모델 초기화 및 테이블 구조 정의
User.init(
{
email: { type: DataTypes.STRING, allowNull: false, unique: true }, // 이메일 필드 (유일하며, 필수)
name: { type: DataTypes.STRING(20), allowNull: false }, // 이름 필드 (20자 제한, 필수)
nickname: { type: DataTypes.STRING(20), allowNull: false, unique: true }, // 닉네임 필드 (20자 제한, 유일하며, 필수)
password: { type: DataTypes.STRING, allowNull: false }, // 비밀번호 필드 (필수)
phone: { type: DataTypes.STRING, allowNull: true }, // 전화번호 필드 (선택적)
},
{
sequelize, // sequelize 인스턴스
modelName: "User", // 모델 이름
tableName: "user", // 테이블 이름
charset: "utf8", // 문자셋 설정
collate: "utf8_general_ci", // 정렬 규칙 설정
}
);
// 관계 설정 (추후 정의할 수 있음)
// export const associate = (db)=>{}
export default User;
import { Sequelize, Options } from "sequelize";
import databaseConfig from "../config/databaseConfig";
import dotenv from "dotenv";
dotenv.config(); // .env 파일에서 환경변수를 불러옴
// 현재 환경(NODE_ENV)에 따라 데이터베이스 환경 설정 선택
const env =
(process.env.NODE_ENV as "production" | "test" | "development") ||
"development";
const { database, username, password } = databaseConfig[env];
console.log(username, password, database, 1111);
console.log(databaseConfig[env]);
// console.log(process.env);
// Sequelize 인스턴스 생성
const sequelize = new Sequelize(database, username, password, {
...(databaseConfig[env] as Options),
});
// 순환 참조를 방지하기 위해 sequelize 인스턴스 내보내기
export { sequelize };
export default sequelize;
import User from "./userModel"; // User 모델 가져오기
export * from "./sequelize"; // sequelize 관련 설정 및 유틸리티 내보내기
// db 객체에 User 모델 포함
const db = { User };
// db 객체의 타입을 정의하는 dbType 타입
export type dbType = typeof db;
import { sequelize } from '../models';
// 데이터베이스 연결을 시도하는 함수
async function waitForDatabase() {
try {
await sequelize.authenticate();
logger.info(
'🤩 Database connection has been established successfully.'
);
return true;
} catch (error) {
logger.error('데이터베이스 연결 실패, 재시도 중...');
return false;
}
}
// Express 애플리케이션을 초기화하는 함수
export default async ({ expressApp }: { expressApp: Application }) => {
try {
// 데이터베이스가 준비될 때까지 기다림
while (!(await waitForDatabase())) {
await new Promise(resolve => setTimeout(resolve, 5000)); // 5초 후 재시도
}
// Express 로더를 통해 필요한 미들웨어 및 라우트 설정
await expressLoader({ app: expressApp });
logger.info('🤩 express loaded'); // Express 로딩 성공 로그