코딩기록

소셜 로그인 구글, 카톡, 페북, 트위터 본문

백엔드

소셜 로그인 구글, 카톡, 페북, 트위터

뽀짝코딩 2022. 8. 4. 09:27
728x90

폴더구조

passport , routes,  app.js와 같은 라인 

구글

https://console.cloud.google.com/apis

 

프론트에서 받을 리다이렉트주소를 적는다

http://localhost:8080/api/auth/google/callback

 

[googleStrategy.js]

require('dotenv').config({ path: `${__dirname}/../../env/passport.env` });
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const db = require('../models');
const Users = db.users;
const Sns = db.sns;

module.exports = () => {
  passport.use(
    new GoogleStrategy(
      {
        clientID: process.env.GOOGLE_ID,
        callbackURL: process.env.GOOGLE_Redirect_URI,
        clientSecret: process.env.GOOGLE_Client_SECRET,
      },

      async (accessToken, refreshToken, profile, done) => {
        console.log('google- profile : ', profile);
        try {
          const exSns = await Sns.findOne({
            where: {
              google: profile.id,
            },
          });
          const duplicateInfo = await Users.findOne({
            where: {
              mail: profile.emails[0].value,
              name: profile.displayName,
            }
          });

          if (exSns === null || exSns) {
            done(null, exSns);
            if (duplicateInfo) {
              await Sns.update({ google: profile.id });
            } else if (null || !duplicateInfo) {
              const newUser = await Users.create({
                email: profile.emails[0].value,
                name: profile.displayName,
                userImg: profile.photos[0].value,
              });
              const newSns = await Sns.create({ google: profile.id });
              done(null, newUser, newSns);
            }
          }
        } catch (error) {
          console.error(error);
          done(error);
        }
      }
    )
  );
};

 

[passport.env]

현재 카카오, 구글, 페이스북만 키를 받았다 

KAKAO_ID=b64255b5da284182038201188d1d91b5
KAKAO_Client_SECRET=pNz08yWR6hiAUB2Zwn4wAxty0Y8IXMmu
KAKAO_Redirect_URI=http://localhost:8080/api/auth/kakao/callback

GOOGLE_ID=940511198541-jd3p040j780sf46pshpfcmmcr4mvbn2f.apps.googleusercontent.com
GOOGLE_Client_SECRET=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
GOOGLE_Redirect_URI=http://localhost:8080/api/auth/google/callback

FACEBOOK_ID=3262489707356407
FACEBOOK_Client_SECRET=11d21edecbb20d9a67b54a9283b00837
FACEBOOK_Redirect_URI=http://localhost:8080/api/auth/facebook/callback

TWITTER_ID=
TWITTER_Client_SECRET=
TWITTER_Redirect_URI=http://localhost:8080/api/auth/twitter/callback

 

 

카카오

https://developers.kakao.com/console/app/766834/product/login

 

프론트에서 받을 리다이렉트주소를 적는다

http://localhost:8080/api/auth/kakao/callback

 

[kakaoStrategy.js]

require('dotenv').config({ path: `${__dirname}/../../env/passport.env` });
const passport = require('passport');
const KakaoStrategy = require('passport-kakao').Strategy;
const db = require('../models');
const Users = db.users;
const Sns = db.sns;

module.exports = () => {
console.log("User",Users)
console.log("Sns",Sns)

  passport.use(
    new KakaoStrategy(
      {
        clientID: process.env.KAKAO_ID,
        callbackURL: process.env.KAKAO_Redirect_URI,
        clientSecret: process.env.KAKAO_Client_SECRET,
      },

      async (accessToken, refreshToken, profile, done) => {
        console.log('kakao- profile:', profile);
        try {
          const exSns = await Sns.findOne({
            // 카카오 플랫폼에서 로그인 했고 & kakao필드에 카카오 아이디가 일치할경우
            where: {
              kakao: profile.id,
            },
          });
          console.log("1111exSns:", exSns)
          const duplicateInfo = await Users.findOne({
            where: {
              email: profile._json.kakao_account.email,
              name: profile.username,
            },
          });
          if (exSns === null || exSns) {
            done(null, exSns);
            if (duplicateInfo) {
              await Sns.update({ kakao: profile.id });
            } else if (null || !duplicateInfo) {
              const newUser = await Users.create({
                email: profile._json && profile._json.kakao_account.email,
                name: profile.username,
                userImg: profile._json.properties.profile_image,
              });
              console.log("newUser22:",newUser)
              const newSns = await Sns.create({ kakao: profile.id });
              console.log("newSns33:",newSns)
              done(null, newUser, newSns);
            }
          }
        } catch (error) {
          console.error(error);
          done(error);
        }
      }
    )
  );
};

 

 

 

페이스북

https://developers.facebook.com/apps/

*참고 문서

https://developers.facebook.com/docs/facebook-login/web

*accessToken 테스트

https://developers.facebook.com/docs/graph-api/guides/explorer

*페북로그인 공식문서
*페북 http로 localhost 테스트 하는방법 

프론트에서 받을 리다이렉트주소를 적는다

http://localhost:8080/api/auth/facebook/callback

 

[facebookStrategy.js]

//https://dev.to/vinhlee95/couldnt-enable-facebook-authentication-via-passport-facebook-in-development-mode-localhost-2im7
require('dotenv').config({ path: `${__dirname}/../../env/passport.env` });
const passport = require('passport');
const FacebookStrategy = require('passport-facebook').Strategy;
const db = require('../models');
const Users = db.users;
const Sns = db.sns;

module.exports = () => {
  passport.use(
    new FacebookStrategy(
      {
        clientID: process.env.FACEBOOK_ID,
        clientSecret: process.env.FACEBOOK_Client_SECRET,
        callbackURL: process.env.FACEBOOK_Redirect_URI,
        profileFields: ['id', 'emails', 'displayName'],
      },
      async (accessToken, refreshToken, profile, done) => {
        const facebook = profile.id;
        const email = profile.emails[0].value;
        const name = profile.displayName;

        console.log('facebook- profile:', profile);
        try {
          const exSns = await Sns.findOne({
            //페이스북 플랫폼에서 로그인 했고 & snsId필드에 페이스북 아이디가 일치할경우
            where: {
              facebook,
            },
          });
          console.log('exSns??', exSns);
          const duplicateInfo = await Users.findOne({
            //디비에 이미 이멜과, 이름이 저장되어있는경우
            where: {
              email,
              name,
            },
          });

          //이미 가입된 구글 프로필 혹은 디비에 이멜과, 이름이 저장되어 있는 경우
          if (exSns === null || exSns) {
            done(null, exSns); //로그인 인증 완료
            if (duplicateInfo) {
              await Sns.update({ facebook });
            } else if (null || !exSns) {
              //가입되지 않는 유저면 회원가입 시키고 로그인을 시킨다
              const newUser = await Users.create({
                email,
                name,
                //userImg: profile._json.properties.profile_image, 없을때 디폴트 하나 넣기
              });
              const newSns = await Sns.create({
                facebook,
              });
              done(null, newUser, newSns); //회원가입하고 로그인 인증 완료
            }
          }
        } catch (error) {
          console.error(error);
          done(error);
        }
      }
    )
  );
};

 

 

 

 

[index.js]

const passport = require('passport');
const kakao = require('./kakaoStrategy'); 
const google = require('./googleStrategy'); 
const facebook = require('./facebookStrategy'); 
// const twitter = require('./twitterStrategy'); 
const User = require('../models/user');
 
module.exports = () => {
   //PASSPORT - 직렬화 
   //serializeUser : 로그인 / 회원가입 후 1회 실행
   passport.serializeUser((user, done) => {
      console.log("index -> serializeUser ", user);
      done(null, user.userId);
   });
   //deserializeUser : 인증 후 페이지 접근시 마다 사용자 정보를 Session에서 읽어옴. 
   passport.deserializeUser((id, done) => { //id인자- 세션에 저장된 사용자 정보
      console.log("index -> deserializeUser id ", id);
      User.findOne({ where: { userId: id } })
         .then(user => done(null, user))
         .catch(err => done(err));
   }); 

   kakao(); // 카카오 전략 등록
   google(); // 구글 전략 등록
   facebook(); // 페이스 전략 등록
   // twitter(); // 트위터 전략 등록
};

[passport.js]

const express = require('express');
const router = express.Router();
const passport = require('passport');
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '../../env/backend.env')});

const { 
  facebookCallback, 
  googleCallback,
  kakaoCallback,
  // twitterCallback,
} = require('../passport/loginCallback');


//페이스북 로그인 라우터
router.get('/facebook', passport.authenticate('facebook', { scope: ['profile', 'email'] }));
router.get('/facebook/callback', facebookCallback);

//구글로 로그인 라우터
router.get('/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
router.get('/google/callback', googleCallback);

//카카오로 로그인 라우터
router.get('/kakao', passport.authenticate('kakao'));
router.get('/kakao/callback', kakaoCallback);

// //트위터 로그인 라우터
// router.get('/twitter', passport.authenticate('twitter'));
// router.get('/twitter/callback', twitterCallback);

module.exports = router;

[loginCallback.js]

require("dotenv").config({ path: `${__dirname}/../../env/backend.env` });
const jwt = require("jsonwebtoken");
const passport = require("passport");

//페이스북 
module.exports.facebookCallback = (req, res, next) => {
  try {
    passport.authenticate('facebook', { failureRedirect: '/' }, (err, user) => {
      if (err) return next(err);
      const { email, name } = user;
      const token = jwt.sign({ userId: user.snsId }, process.env.TOKENKEY, {
        expiresIn: process.env.JWT_ACCESS_EXPIRE,
      });
      console.log('auth의 페이스북token:', token);
      result = {
        token,
        email,
        name,
      };
      console.log('auth의 페이스북result:', result);
      res.json({ user: result });
    })(req, res, next);
  } catch (err) {
    console.log('페이스북callback err: ', err);
    res.status(400).json({
      ok: false,
      errorMessage: `요청한 데이터 형식이 올바르지 않습니다 `,
    });
  }
};

//구글
module.exports.googleCallback = (req, res, next) => {
  try {
    passport.authenticate('google', { failureRedirect: '/' }, (err, user) => {
      if (err) return next(err);
      const { email, name } = user;
      const token = jwt.sign({ userId: user.snsId }, process.env.TOKENKEY, {
        expiresIn: process.env.JWT_ACCESS_EXPIRE,
      });
      console.log('auth의 구글token:', token);
      result = {
        token,
        email,
        name,
      };
      console.log('auth의 구글result:', result);
      res.json({ user: result });
    })(req, res, next);
  } catch (err) {
    console.log('구글callback err: ', err);
    res.status(400).json({
      ok: false,
      errorMessage: `요청한 데이터 형식이 올바르지 않습니다 `,
    });
  }
};


//카카오톡
module.exports.kakaoCallback = (req, res, next) => {
  try {
    passport.authenticate('kakao', { failureRedirect: '/' }, (err, user) => {
      if (err) return next(err);
      const { email, name } = user;
      //토큰 발행
      const token = jwt.sign({ userId: user.snsId }, process.env.TOKENKEY, {
        expiresIn: process.env.JWT_ACCESS_EXPIRE,
      });
      console.log('auth의 카톡token:', token);
      result = {
        token,
        email,
        name,
      };
      console.log('auth의 카톡result:', result);
      res.json({ user: result });
    })(req, res, next);
  } catch (err) {
    console.log('카톡callback err: ', err);
    res.status(400).json({
      ok: false,
      errorMessage: `요청한 데이터 형식이 올바르지 않습니다 `,
    });
  }
};


// //트위터
// module.exports.twitterCallback = (req, res, next) => {
//   try{
//     passport.authenticate('twitter', { failureRedirect: '/' }, (err, user) => {
//       if (err) return next(err);
//       const { email, name } = user;
//       const token = jwt.sign({ userId: user.snsId }, process.env.TOKENKEY, {
//         expiresIn: process.env.JWT_ACCESS_EXPIRE,
//       });
//       console.log('auth의 트위터token:', token);
//       result = {
//         token,
//         email,
//         name,
//       };
//       console.log('auth의 트위터result:', result);
//       res.json({ user: result });
//     })(req, res, next);
//   } catch (err) {
//     console.log('트위터callback err: ', err);
//     res.status(400).json({
//       ok: false,
//       errorMessage: `요청한 데이터 형식이 올바르지 않습니다 `,
//     });
//   }
// };

 

 

참고

*카카오문서보고 구현함

https://injekim97.tistory.com/137

 

 

 

 

 

 

반응형
Comments