개인공부/Node.js

nodejs로 SNS 만들기 #3

psys 2022. 8. 15. 15:27
728x90

https://yeon960.tistory.com/271

 

nodejs로 SNS 만들기 #2

https://yeon960.tistory.com/270 nodejs로 SNS 만들기 #1 1. 프로젝트 세팅 시작 1. package.json 생성하기 $npm init 2. package.json 작성하기 { "name": "nodeinsta", "version": "1.0.0", "description": "노..

yeon960.tistory.com

이전편(프로젝트 세팅)은 요기👆

 


Passport 모듈로 로그인 구현하기

1. passport관련 패키지 설치

$npm i passport passport-local passport-kakao bcrypt

 

2. app.js와 연결

//app.js
...
const flash = require('connect-flash');
const passport = require('passport'); // 추가1-passport모듈과 연결

require('dotenv').config(); // 비밀키 불러오기

const pageRouter = require('./routes/page'); // 라우터 가져오기
const { sequelize } = require('./models'); // 모델 서버 연결
const passportConfig = require('./passport'); // 추가2-passport모듈과 연결
...
const app = express();
sequelize.sync(); // 모델 서버 연결
passportConfig(passport); // 추가3-passport모듈과 연결
...
app.use(flash());
app.use(passport.initialize()); // 추가4-요청(req)에 passport설정 심어줌
app.use(passport.session()); // 추가5-req.session객체에 passport정보를 저장

 

3. 모듈 작성

app.js와 연결했던 Passport 모듈 작성

// passport.index.js
const local = require('./localStrategy');
const kakao = require('./kakaoStrategy');
const { User } = require('../models');

module.exports = (passport) => {
  passport.serializeUser((user, done) => {
    done(null, user.id);
  });

  passport.deserializeUser((id, done) => {
    User.findOne({ where: { id } })
      .then(user => done(null, user))
      .catch(err => done(err));
  });

  local(passport);
  kakao(passport);
};

 

4. 로컬 로그인 구현

1) middlewares.js 추가

// routes/middlewares.js
exports.isLoggedIn = (req, res, next) => {
    if (req.isAuthenticated()) {
      next();
    } else {
      res.status(403).send('로그인 필요');
    }
  };
  
  exports.isNotLoggedIn = (req, res, next) => {
    if (!req.isAuthenticated()) {
      next();
    } else {
      res.redirect('/');
    }
  };

 

2) page.js 수정

// routes/page.js
const express = require('express');
const { isLoggedIn, isNotLoggedIn } = require('./middlewares'); // 추가1

const router = express.Router();

// http://localhost:8001/profile
router.get('/profile', (req, res) => {
  res.render('profile', { title: '내 정보 - NodeInsta', user: req.user }); // 추가2
});

// http://localhost:8001/join
router.get('/join', (req, res) => {
  res.render('join', {
  		title: '회원가입 - NodeInsta',
        user: req.user, // 추가3
        joinError: req.flash('joinError'),
	});
});

// http://localhost:8001/
router.get('/', (req, res, next) => {
  res.render('main', {
        title: 'NodeBird',
        twits: [],
        user: req.user, // 추가4
        loginError: req.flash('loginError'),
	});
});

module.exports = router;

 

3) auth.js 추가

// routes/auth.js
const express = require('express');
const passport = require('passport');
const bcrypt = require('bcrypt');
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');
const { User } = require('../models');

const router = express.Router();

router.post('/join', isNotLoggedIn, async (req, res, next) => {
  const { email, nick, password } = req.body;
  try {
    const exUser = await User.findOne({ where: { email } });
    if (exUser) {
      req.flash('joinError', '이미 가입된 이메일입니다.');
      return res.redirect('/join');
    }
    const hash = await bcrypt.hash(password, 12);
    await User.create({
      email,
      nick,
      password: hash,
    });
    return res.redirect('/');
  } catch (error) {
    console.error(error);
    return next(error);
  }
});

router.post('/login', isNotLoggedIn, (req, res, next) => {
  passport.authenticate('local', (authError, user, info) => {
    if (authError) {
      console.error(authError);
      return next(authError);
    }
    if (!user) {
      req.flash('loginError', info.message);
      return res.redirect('/');
    }
    return req.login(user, (loginError) => {
      if (loginError) {
        console.error(loginError);
        return next(loginError);
      }
      return res.redirect('/');
    });
  })(req, res, next); // 미들웨어 내의 미들웨어에는 (req, res, next)를 붙입니다.
});

router.get('/logout', isLoggedIn, (req, res) => {
  req.logout();
  req.session.destroy();
  res.redirect('/');
});

router.get('/kakao', passport.authenticate('kakao'));

router.get('/kakao/callback', passport.authenticate('kakao', {
  failureRedirect: '/',
}), (req, res) => {
  res.redirect('/');
});

module.exports = router;

4) localStrategy.js

// passport/localStrategy.js
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');

const { User } = require('../models');

module.exports = (passport) => {
  passport.use(new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
  }, async (email, password, done) => {
    try {
      const exUser = await User.findOne({ where: { email } });
      if (exUser) {
        const result = await bcrypt.compare(password, exUser.password);
        if (result) {
          done(null, exUser);
        } else {
          done(null, false, { message: '비밀번호가 일치하지 않습니다.' });
        }
      } else {
        done(null, false, { message: '가입되지 않은 회원입니다.' });
      }
    } catch (error) {
      console.error(error);
      done(error);
    }
  }));
};

 

5. 카카오 로그인 구현

1) kakaoStrategy.js 추가

// passport/kakaoStrategy.js
const KakaoStrategy = require('passport-kakao').Strategy;

const { User } = require('../models');

module.exports = (passport) => {
  passport.use(new KakaoStrategy({
    clientID: process.env.KAKAO_ID,
    callbackURL: '/auth/kakao/callback',
  }, async (accessToken, refreshToken, profile, done) => {
    try {
      const exUser = await User.findOne({ where: { snsId: profile.id, provider: 'kakao' } });
      if (exUser) {
        done(null, exUser);
      } else {
        const newUser = await User.create({
          email: profile._json && profile._json.kaccount_email,
          nick: profile.displayName,
          snsId: profile.id,
          provider: 'kakao',
        });
        done(null, newUser);
      }
    } catch (error) {
      console.error(error);
      done(error);
    }
  }));
};

 

2) auths.js 수정

// routes/auth.js
...
/* 추가 시작 */
router.get('/kakao', passport.authenticate('kakao'));

router.get('/kakao/callback', passport.authenticate('kakao', {
  failureRedirect: '/',
}), (req, res) => {
  res.redirect('/');
});
/* 추가 끝 */

module.exports = router;

 

3) app.js 수정

// app.js
...
const pageRouter = require('./routes/page'); // 라우터 가져오기
const authRouter = require('./routes/auth');
...
app.use('/', pageRouter);
app.use('/auth', authRouter);
...

 

4) clientID 발급

kakaoStrategy.js의 clientID 부분을 발급받는다.

카카오 로그인을 위해 카카오 개발자 계정과 카카오용 앱이 필요하다.

https://developers.kakao.com 에 접속하여 회원가입 후 아래의 절차에 따라보자.

 

카카오용 nodeInsta 앱을 만든다.

 

앱 생성 후 REST API키를 복사하여 .env 파일에 넣어준다.

 

5) .env 수정

// .env
COOKIE_SECRET=nodeInstasecret
KAKAO_ID= //rest api 값

 

6) 내 애플리케이션>앱 설정>플랫폼>web 플랫폼 등록

http://localhost:8001 입력

 

7) Redirect URI를 등록

등록된 사이트 도메인 밑에 등록하러 가기 url 클릭.

8) redirect URL 추가

http://localhost:8001/auth/kakao/callback

 

9) redirect URL 추가하는 곳 바로 위에 활성화 설정에 활성화 on으로

 

6. 서버실행

$npm start

http://localhost:8001/에 접속하여 카카오 로그인 확인

 

7. 확인하기

아래와 같이 카카오 로그인이나 회원가입이 뜨면 성공~~


다음편(이미지 업로드 구현)은 요기👇

https://yeon960.tistory.com/274

 

Node.jsnodejs로 SNS 만들기 #4

https://yeon960.tistory.com/272 nodejs로 SNS 만들기 #3 https://yeon960.tistory.com/271 nodejs로 SNS 만들기 #2 https://yeon960.tistory.com/270 nodejs로 SNS 만들기 #1 1. 프로젝트 세팅 시작 1. package...

yeon960.tistory.com