Configuration

유석현(SeokHyun Yu)·2022년 12월 9일
0

Node.js

목록 보기
21/29
post-thumbnail

.env

JWT_SECRET_KEY=secret
JWT_EXPIRES=5m
BCRYPT_SALT_ROUNDS=12
SERVER_PORT=8000

config.js

import dotenv from "dotenv";

// .env에 작성한 환경 변수를 현재 서버 세션의 환경에 등록해준다
dotenv.config();

export const config = {
    jwtSecretKey: process.env.JWT_SECRET_KEY,
    jwtExpires: process.env.JWT_EXPIRES,
    bcryptSaltRounds: parseInt(process.env.BCRYPT_SALT_ROUNDS),
    port: parseInt(process.env.SERVER_PORT),
};

app.js

import express from "express";
import helmet from "helmet";
import morgan from "morgan";
import cors from "cors";
import tweetController from "./tweet/tweet.controller.js";
import authController from "./auth/auth.controller.js";
import { config } from "../config.js";

// 서버 생성
const app = express();

// 미들웨어
app.use(express.json());
app.use(morgan("dev"));
app.use(helmet());
app.use(cors());

// 라우터
app.use("/tweet", tweetController);
app.use("/auth", authController);

// 404 에러 핸들러
app.use((req, res, next) => {
    res.sendStatus(404);
});

// 500 에러 핸들러
app.use((err, req, res, next) => {
    res.sendStatus(500);
});

// 8000 포트로 listen
// 환경 변수 사용
app.listen(config.port);

auth.js

import jwt from "jsonwebtoken";
import { config } from "../../config.js";
import * as userRepository from "../user/user.repository.js";

export const auth = async (req, res, next) => {
    // Header의 Authorization 키 안에 담겨있는 토큰을 가져온다
    const authHeader = req.get("Authorization");

    // 토큰이 있고 "Bearer"로 시작하는 토큰이라면
    if (authHeader && authHeader.startsWith("Bearer ")) {
        // "Bearer"와 토큰 string을 분리
        const token = authHeader.split(" ")[1];

        // 토큰값 검증
      	// 환경 변수 사용
        jwt.verify(token, config.jwtSecretKey, async (err, data) => {
            // 토큰이 유효하지 않다면
            if (err) {
                return res.status(401).json({ message: "인증 에러" });
            }
            // 토큰이 유효하다면
            else {
                // 토큰이 유효하더라도 토큰에 담겨있는 id값이 실제로 존재하는지 한 번 더 확인
                const user = await userRepository.findById(data.id);

                // 유저가 존재하면
                if (user) {
                    req.token = token;
                    req.userId = user.id;

                    return next();
                }
                // 유저가 존재하지 않다면
                else {
                    return res.status(401).json({ message: "인증 에러" });
                }
            }
        });
    }
    // 위의 if 문에는 return 문이 없다
    // jwt.verify의 콜백 함수 안에서 return을 하긴 하지만 비동기로 동작한다
    // 따라서 else로 묶어주지 않으면 아래의 return 문까지 실행된다
    else {
        return res.status(401).json({ message: "인증 에러" });
    }
};

auth.service.js

import * as userRepository from "../user/user.repository.js";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { config } from "../../config.js";

const createToken = (id) => {
  	// 환경 변수 사용
    return jwt.sign({ id }, config.jwtSecretKey, {
        expiresIn: config.jwtExpires,
    });
};

// 회원가입
export const signup = async (req, res) => {
    const { username, password, name, email } = req.body;

    // 이미 가입된 유저일 경우
    const user = await userRepository.findByUsername(username);

    if (user) {
        return res.status(409).json({ message: `이미 가입된 유저입니다.` });
    }

    // 비밀번호 암호화
  	// 환경 변수 사용
    const hashed = await bcrypt.hash(password, config.bcryptSaltRounds);

    // 유저 데이터 생성
    const createdUser = await userRepository.createUser({
        username,
        password: hashed,
        name,
        email,
    });

    // 토큰 생성
    const token = createToken(createdUser.id);

    res.status(201).json({ token, username });
};

// 로그인
export const login = async (req, res) => {
    const { username, password } = req.body;

    // username을 가진 유저가 있는지 확인
    const user = await userRepository.findByUsername(username);

    if (!user) {
        return res
            .status(401)
            .json({ message: "아이디 혹은 비밀번호가 틀렸습니다." });
    }

    // bcrypt.compare()로 암호화 된 비밀번호와 비교
    const isValidPassword = await bcrypt.compare(password, user.password);

    if (!isValidPassword) {
        return res
            .status(401)
            .json({ message: "아이디 혹은 비밀번호가 틀렸습니다." });
    }

    // 토큰 생성
    const token = createToken(user.id);

    res.status(200).json({ token, username });
};

// me
export const me = async (req, res) => {
    const user = await userRepository.findById(req.userId);

    if (user) {
        return res
            .status(200)
            .json({ token: req.token, username: user.username });
    }

    res.status(404).json({ message: "유저가 존재하지 않습니다." });
};
profile
Backend Engineer

0개의 댓글