Skip to content
Snippets Groups Projects
Select Git revision
  • ac3908a67a720d89ff1931dffeee75997b780fdc
  • main default
2 results

app.js

Blame
  • app.js 14.28 KiB
    const express = require('express');
    const app = express();
    
    const mongoose = require('mongoose');
    const cors = require('cors');
    //app.use(express.urlencoded({ extended: false }));
    const passport = require('./config/passport');
    //const cookieParser = require('cookie-parser');
    const cookieParser = require('cookie-parser');
    app.use(cookieParser());
    app.use(passport.initialize());
    //const session = require('express-session');
    const jwt = require('jsonwebtoken');
    require('dotenv').config();
    const secretKey = process.env.JWT_SECRET; // 실제 환경에서는 환경 변수로 관리하세요.
    const refreshTokenSecretKey = process.env.JWT_REFRESH_SECRET;
    
    const https = require('https');
    const fs = require('fs');
    const expressSanitizer = require('express-sanitizer');
    
    app.use(express.json());
    app.use(express.urlencoded({ extended: true }));
    app.use(expressSanitizer());
    app.use('/', express.static('public'));
    
    // SSL 인증서와 개인 키 파일 경로 설정
    // SSL 옵션 설정
    const sslOptions = {
        key: fs.readFileSync('./cert/server.key'),
        cert: fs.readFileSync('./cert/server.cert'),
      };
    
    // // HTTP 서버 설정 (포트 8001)
    // const HTTP_PORT = 8001;
    // app.listen(HTTP_PORT, () => {
    //   console.log(`HTTP server started on port ${HTTP_PORT}`);
    // });
    
    // // HTTPS 서버 설정 (포트 8080)
    // const HTTPS_PORT = 8080;
    // https.createServer(options, app).listen(HTTPS_PORT, () => {
    //   console.log(`HTTPS server started on port ${HTTPS_PORT}`);
    // });
    
    //middleware
    app.use(cors({
        origin: "https://localhost:3000",
        credentials: true, //쿠키전송 허용
        methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
        allowedHeaders: ['Content-Type', 'Authorization']
    }));
    //비밀번호 변경 라우트 등록
    const passwordRoutes = require('./route/conf_password');
    //닉네임 변경 라우트 등록
    const confNameRoutes = require('./route/conf_name.js');
    //회원 탈퇴 라우트 등록
    const deleteUser = require('./route/del_user');
    //비밀번호 암호화용 모듈
    const bcrypt = require('bcrypt');
    //User define
    const User = require('./models/user');
    //Trip define
    const Trip = require('./models/trips');
    //Favorite define
    const Favorite = require('./models/favorite');
    // JSON 요청 본문을 파싱하는 미들웨어 추가
    app.use(express.json());
    //비밀번호 변경 라우트 추가
    app.use('/conf_password',passwordRoutes);
    //이름 변경 라우트
    app.use('/conf_name', confNameRoutes);
    //회원 탈퇴 라우트
    app.use('/del_user', deleteUser); 
    
    //여행 라우트
    const tripRoutes = require('./route/tripRoute'); // 라우트 파일 경로
    // Routes
    app.use('/api/trips', tripRoutes);
    //리뷰 라우트
    const reviewRoutes = require('./route/review'); // 라우트 파일 경로
    app.use('/api/review', reviewRoutes);
    //dotenv
    require('dotenv').config();
    //favorite 라우트
    const favoriteRoutes = require('./route/favorites'); // 라우트 파일 경로
    app.use('/favorites', favoriteRoutes);
    
    const authenticateToken = require('./middleware/authMiddleware.js');
    
    // 보호된 라우트에 미들웨어 적용
    app.use('/conf_password', authenticateToken, passwordRoutes);
    app.use('/conf_name', authenticateToken, confNameRoutes);
    app.use('/del_user', authenticateToken, deleteUser);
    
    //확인
    console.log('GOOGLE_CLIENT_ID:', process.env.GOOGLE_CLIENT_ID);
    console.log('GOOGLE_CLIENT_SECRET:', process.env.GOOGLE_CLIENT_SECRET);
    
    
    
    
    // // MongoDB 연결
    // mongoose.connect('mongodb://localhost:27017/logininfo', {
    //     useNewUrlParser: true,
    //     useUnifiedTopology: true,
    // }).then(() => console.log('MongoDB 연결 성공'))
    //   .catch(err => console.error('MongoDB 연결 오류:', err));
    
    // application/x-www-form-urlencoded
    app.use(express.urlencoded({ extended: false }));
    
    // db connect
    mongoose
      .connect(process.env.mongoURL, {
        useNewUrlParser: true,
        useUnifiedTopology: true,
        dbName: "festivelo_DB" // 이 이름으로 db가 생성됩니다.
      })
      .then(() => {console.log(`MongoDB connected to festivelo_DB`);
      // DB 연결 확인
      const db = mongoose.connection;
      console.log('Current database:', db.name);
    })
      .catch((err) => console.error(err));
    
    // 세션 설정
    // app.use(session({
    //     secret: 'your_secret_key',
    //     resave: false,
    //     saveUninitialized: false,
    // }));
    
    // Passport 초기화
    //app.use(passport.initialize());
    //app.use(passport.session());
    
    // Google 로그인 라우트
    app.get('/googlelogin',
        passport.authenticate('google', { scope: ['profile', 'email'], session: false })
    );
    
    //jwt 전--------------------------------------
    // app.get('/googlelogin/redirect',
    //     passport.authenticate('google', { failureRedirect: '/' }),
    //     (req, res) => {
    //         const userInfo = encodeURIComponent(JSON.stringify({
    //             _id: req.user._id,
    //             email: req.user.email,
    //             name: req.user.name
    //         }));
    //         // 로그인 성공 시 리다이렉트
    //         res.redirect(`http://localhost:3000/login?user=${userInfo}`);
    //         console.log(`구글 로그인 성공: ${userInfo}`);
    
    //     }
    // );
    //----------------------------------------------
    
    //jwt 후-----------------------------------------
    app.get('/googlelogin/redirect',
        passport.authenticate('google', { failureRedirect: '/', session: false }),
        async (req, res) => {
            const accessToken = jwt.sign(
                { userId: req.user._id, email: req.user.email, name: req.user.name },
                secretKey,
                { expiresIn: '15m' }
            );
            const refreshToken = jwt.sign(
                { userId: req.user._id },
                refreshTokenSecretKey,
                { expiresIn: '7d' } // 리프레시 토큰 유효 기간: 7일
            );
    
            // 토큰 로그 출력
            console.log('생성된 액세스 토큰:', accessToken);
            console.log('생성된 리프레시 토큰:', refreshToken);
    
            // 사용자 데이터베이스에 리프레시 토큰 저장
            req.user.refreshToken = refreshToken;
            await req.user.save();
    
            // 쿠키에 토큰 저장
            res.cookie('accessToken', accessToken, {
                httpOnly: true,
                secure: true,
                sameSite: 'Strict',
                maxAge: 15 * 60 * 1000 // 15분
            });
    
            res.cookie('refreshToken', refreshToken, {
                httpOnly: true,
                secure: true,
                sameSite: 'Strict',
                maxAge: 7 * 24 * 60 * 60 * 1000 // 7일
            });
            //res.redirect(`http://localhost:3000/login#token=${token}`);
            res.redirect('https://localhost:3000/');
            console.log(`구글 로그인 성공: ${req.user.email}`);
        }
    );
    //-------------------------------------------------
    
    // 로그아웃
    app.get('/logout', async(req, res) => {
        // req.logout((err) => {
        //     if (err) { return next(err); }
        //     res.redirect('/');
        // });
        //res.clearCookie('token'); //쿠키삭제
        const refreshToken = req.cookies.refreshToken;
    
        // 리프레시 토큰 무효화
        if (refreshToken) {
            try {
                const decoded = jwt.verify(refreshToken, refreshTokenSecretKey);
                const user = await User.findById(decoded.userId);
                if (user) {
                    user.refreshToken = null;
                    await user.save();
                }
            } catch (err) {
                console.error('리프레시 토큰 검증 오류:', err);
            }
        }
    
        // 쿠키 삭제
        res.clearCookie('accessToken');
        res.clearCookie('refreshToken');
        res.redirect('/');
    });
    
    // 토큰 재발급 엔드포인트
    app.post('/token', async (req, res) => {
        const refreshToken = req.cookies.refreshToken;
    
        if (!refreshToken) return res.sendStatus(401);
    
        try {
            const decoded = jwt.verify(refreshToken, refreshTokenSecretKey);
            const user = await User.findById(decoded.userId);
    
            if (!user || user.refreshToken !== refreshToken) {
                return res.sendStatus(403);
            }
    
            const newAccessToken = jwt.sign(
                { userId: user._id, email: user.email, name: user.name },
                secretKey,
                { expiresIn: '15m' }
            );
    
            res.cookie('accessToken', newAccessToken, {
                httpOnly: true,
                secure: true,
                sameSite: 'Strict',
                maxAge: 15 * 60 * 1000 // 15분
            });
    
            res.status(200).json({ message: '토큰 재발급 성공' });
        } catch (error) {
            console.error('토큰 재발급 오류:', error);
            res.sendStatus(403);
        }
    });
    
    // 대시보드
    app.get('/dashboard', authenticateToken, (req, res) => {
    
        //const hasPassword = !!req.user.password; // 비밀번호가 있는지 확인
        //const userName = req.user.name || req.user.email || 'Guest';
    
        res.send(`
            <h1>Welcome, ${userName}}</h1>
            <a href="/conf_name/change">사용할 이름 변경</a>
            <br>
            ${hasPassword ? '<a href="/conf_password/change">비밀번호 변경</a>' : ''}
            <br>
            <a href="/logout">Logout</a>
        `);
    });
    
    // // 홈
    // app.get('/', (req, res) => {
    //     res.send(`
    //         <h1>Google OAuth Login</h1>
    //         <a href="/googlelogin">Login with Google</a>
    //     `);
    // });
    
    //signup 경로
    app.get('/signup', (req, res) => {
        res.sendFile(__dirname + '/public/signup.html'); // login.html 파일 경로 설정
    });
    
    //session
    // app.get('/conf_password', (req, res) => {
    
    //     if (req.isAuthenticated && req.isAuthenticated()) { // 로그인 여부 확인
    //         res.sendFile(__dirname + '/public/conf_password.html');
    //     }
    // });
    //jwt
    app.get('/conf_password', authenticateToken, (req, res) => {
        res.sendFile(__dirname + '/public/conf_password.html');
    });
    
    
    //홈 - index.html
    app.use(express.static('public'));
    
    //일반 로그인
    app.post('/login', async (req, res) => {
        const { email, password } = req.body;
        console.log('로그인 요청:', email, password);  // 추가된 로그
        try {
            // 사용자가 존재하는지 확인
            const user = await User.findOne({ email });
            if (!user) {
                return res.status(400).json({ message: '사용자를 찾을 수 없습니다.' });
            }
            //password 정보 없는 유저 -> 구글 로그인 사용자
            if (!user.password) {
                return res.status(400).json({ message: '사용자를 찾을 수 없습니다.' });
            }
    
            
    
            // 비밀번호 검증
            const isMatch = await bcrypt.compare(password, user.password);
            if (!isMatch) {
                return res.status(400).json({ message: '비밀번호가 일치하지 않습니다.' });
            }
    
            // 로그인 성공 시 사용자 세션에 저장 - 세션 로그인
            // req.login(user, (err) => {
            //     if (err) {
            //         console.error('로그인 세션 저장 오류:', err);
            //         return res.status(500).json({ message: '로그인 세션 저장 중 오류가 발생했습니다.' });
            //     }
            //     res.status(200).json({ message: '로그인 성공', user: {
            //         _id: user._id,
            //         email: user.email,
            //         name: user.name
            //     } });
            //     console.log('로그인 성공: ', user);
    
            //jwt---------------------------------------
            const accessToken = jwt.sign(
                { userId: user._id, email: user.email, name: user.name },
                secretKey,
                { expiresIn: '15m' }
            );
    
            const refreshToken = jwt.sign(
                { userId: user._id },
                refreshTokenSecretKey,
                { expiresIn: '7d' }
            );
    
            // 사용자 데이터베이스에 리프레시 토큰 저장
            user.refreshToken = refreshToken;
            await user.save();
    
            //https 환경에서만
            res.cookie('accessToken', accessToken, {
                httpOnly: true,
                secure: true, // 프로덕션 환경에서만 secure 플래그 활성화
                sameSite: 'Strict', // CSRF 방지를 위해 sameSite 옵션 설정
                maxAge: 3600000 // 1시간 (토큰 만료 시간과 동일하게 설정)
            });
    
            res.status(200).json({
                message: '로그인 성공',
                accessToken: accessToken,
                user: {
                    _id: user._id,
                    email: user.email,
                    name: user.name
                }
            });
        } catch (error) {
            console.error('로그인 오류:', error);
            res.status(500).json({ message: '서버 오류가 발생했습니다.' });
        }
    });
    
    
    
    //웹사이트 내 회원가입
    app.post('/signup', async (req, res) => {
        const { email, password, name } = req.body;
    
        try {
            // 존재하는 사용자 확인
            let user = await User.findOne({ email });
            if (user) {
                return res.status(400).json({ message: '이미 존재하는 사용자입니다.' });
            }
    
            // 비밀번호 암호화
            const hashedPassword = await bcrypt.hash(password, 10);
    
            // 새 사용자 생성 및 저장
            user = new User({
                email,
                password: hashedPassword, // 암호화된 비밀번호 저장
                name,
            });
            await user.save();
    
            // if((!user.password)||(!user.email)||(!user.name)){
            //     res.status(500).json({ message: '요청 정보가 누락되었습니다.'});
            // }
    
            res.status(201).json({ message: '회원가입 성공' });
        } catch (error) {
            console.error('회원가입 오류:', error);
            res.status(500).json({ message: '서버 오류가 발생했습니다.' });
        }
    });
    
    app.get('/auth/status', authenticateToken, (req, res) => {
        res.status(200).json({
          isAuthenticated: true,
          user: {
            _id: req.user.userId,
            email: req.user.email,
            name: req.user.name
          }
        });
      });
      
    
    // app.listen(process.env.PORT, () => {
    //     console.log(`Server is running on http://localhost:${process.env.PORT}`);
    // });
    
    // HTTPS 강제 적용 미들웨어 (선택 사항)
    app.use((req, res, next) => {
        if (req.secure || req.headers['x-forwarded-proto'] === 'https') {
          next();
        } else {
          res.redirect(`https://${req.headers.host}${req.url}`);
        }
      });
    
    https.createServer(sslOptions, app).listen(process.env.PORT || 8000, () => {
        console.log(`HTTPS 서버가 실행 중입니다: https://localhost:${process.env.PORT || 8000}`);
      });
      
    // HTTP 서버 실행 (선택 사항)
    // http.createServer(app).listen(8080, () => {
    //     console.log('HTTP 서버가 실행 중입니다: http://localhost:8080');
    //   });