SNS서비스 Project 3

회원가입, 로그인(KAKAO)

Posted by ETHAN KIM on November 10, 2021 · 11 mins read
Node.js

1. 로그인 구현하기

passport 모듈로 passport설정 및 실행파일 export

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

module.exports = () => {
    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();
    kakao();
};


2. 로그인 여부를 위한 모듈

middleware를 통해 로그인 여부를 판단하여 각 페이지에 제한을 둔다.

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{
        const message = encodeURIComponent('로그인한 상태입니다.');
        res.redirect(`/?error = ${message}`);
    }
};


3. 로그인전략

page라우터에서 post join요청일 경우 회원가입 전략 post login일 경우 local 로그인 전략을 실행한다. get kakao일 경우 kakao전략 실행

routes.auth.js

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

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){
            return res.redirect('/join?error=exist');
        }
        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){
            return res.redirect(`/?loginError=${info.message}`);
        }
        return req.login(user, (loginError) => {
            if(loginError){
                console.error(loginError);
                return next(loginError);
            }
            return res.redirect('/');
        });
    })(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. local 전략

로그인 결과를 callback함수로 auth페이지에 전달


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

const User = require('../models/user');

module.exports = () => {
    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. KAKAO 로그인 전략

KAKAO 페이지와 연동한 키를 사용하여, 회원이 아닐 경우 회원정보를 전달받아 insert 회원일 경우 로그인 전략 실행 후 callback함수 실행


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

const User = require('../models/user');

module.exports = () => {
    passport.use(new KakaoStrategy({
        clientID: process.env.KAKAO_ID,
        callbackURL:'/auth/kakao/callback',
    }, async (accessToken, refreshToken, profile, done) => {
        console.log('kakao profile', profile);
        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.kakao_account_email,
                    nick: profile.displayName,
                    snsId: profile.id,
                    profider: 'kakao',
                });
                done(null, newUser);
            }
        }catch(error){
            console.error(error);
            done(error);
        }
    }));
}


카카오 개발자 페이지를 통해 로그인용 애플리케이션 등록이 필요하다.





카카오 로그인시


회원가입


local로 로그인시