관리 메뉴

나의 개발일지(김지헌)

항해 99 64일차 11/21일 본문

항해 99

항해 99 64일차 11/21일

코딩이좋아요 2022. 11. 22. 03:11

오늘은 카카오 소셜 로그인 하기를 구현했다.(티스토리 인파님꺼를 참고해서 작성했습니다.)

 

경로를 /kakao로 정해줬고 요청이 들어오면 

passport.authenticate('kakao',  라는쪽으로 요청을 보내줘서 카카오 화면이 불러와진다

그다음 {scope: ['profile_nickname', 'profile_image'],})
scope에 있는 닉네임과 이미지가 담겨서 passport index.ts로 이동한다.

//kakao 라우터

import { Router } from 'express';
import passport from 'passport';
import dotenv from 'dotenv'
import kakaoCallback from '../../utils/kakaojwt'
dotenv.config()
const router = Router();

//kakao로 요청오면, 카카오 로그인 페이지로 가게 되고, 카카오 서버를 통해 카카오 로그인을 하게 되면, 다음 라우터로 요청한다.
router.get('/',passport.authenticate('kakao', {scope: ['profile_nickname', 'profile_image'],})
); //scope 속성



router.get('/callback',kakaoCallback);

export default router;

라우터에서 index.ts으로 요청이 보내지며 주석처리된 코드는 필요 없어서 사용하지 않는다 밑에

kakao()함수를 실행하면서 카카오 스토리지로 요청이 보내진다

import passport from 'passport';
import User from '../database/models/user';
import kakao from './kakaoSrategy';

export default () => {
  //serializeUser => 사용자 정보 객체를 세션에 아이디로 저장
  // passport.serializeUser((user,done)=>{
  //   console.log(user,"sdafsdafsdafdasfdsa")
  //   // const userId = user.id
  //   // done(null, user); //user.id 가능
  // })

  // //deserializeUser => 세션에 저장한 아이디를 통해서 사용자 정보 객체를 불러옴
  // passport.deserializeUser((id, done) => {
  //   //? 두번 inner 조인해서 나를 팔로우하는 followerid와 내가 팔로우 하는 followingid를 가져와 테이블을 붙인다
  //   User.findOne({ where: { id } })
  //      .then(user => done(null, user))
  //      .catch(err => done(err));
  // });
  kakao(); //카카오 실행
};

 

import passport from 'passport';
import dotenv from 'dotenv';
import { User } from '../database/models/user';
import { profile } from '../interface/user';
dotenv.config();
const KakaoPassport = require('passport-kakao').Strategy;
//Strategy => 카카오톡 스토리지 안에있는 클래스 적용
//KakaoPassport => 인터페이스 및 클래스 사용

export default () => {
  //passport 카카오가 정한 인터페이스
  passport.use(
    new KakaoPassport(
      {
        clientID: process.env.KAKAO_ID!,
        callbackURL: process.env.KAKAO_URL!,
      },
      async (accessToken: string, refreshToken: string, profile: profile, done: any) => {
        try {
          const profileImg = profile._json.properties.profile_image;
          const kakaoId = profile._json.id;
          const nickname = profile._json.properties.nickname;
          const exUser = await User.findOne({
            // 카카오 플랫폼에서 로그인 했고 & snsId필드에 카카오 아이디가 일치할경우
            where: { kakaoId, provider: 'kakao' },
          });
          // 이미 가입된 카카오 프로필이면 성공
          if (exUser) {
            done(null, exUser); // 로그인 인증 완료
          } else {
            // 가입되지 않는 유저면 회원가입 시키고 로그인을 시킨다
            const newUser = await User.create({
              kakaoId: kakaoId,
              nickname: nickname,
              provider: 'kakao',
              profileImg: profileImg,
            });
            done(null, newUser); // 회원가입하고 로그인 인증 완료
          }
        } catch (err) {
          console.error(err);
          done(err);
        }
      }
    )
  );
};

로직이 실행되면서 done(null,newUser)쪽으로 이동하면서 라우터에있는 kakao/callback으로 넘어간다.

import { NextFunction, Request, Response } from "express";
import passport from "passport";
import jwt from "jsonwebtoken";
import { Users } from "../interface/user";
import bcrypt from 'bcrypt';
import User from "../database/models/user";

export default(req:Request, res:Response, next:NextFunction) => {
  try {
    console.log("test");
    passport.authenticate(
      "kakao",
      { failureRedirect: "/login" }, // 실패하면 '/user/login''로 돌아감.
      async (err:Error, user:Users) => {
        console.log(user)
        //에러가 났다면
        if (err) return next(err);
        const { userId } = user;
        const AccessToken = jwt.sign(
          { userId: userId },
          process.env.JWT_KEY!,
          { expiresIn: "3h" }
        );
        const RefreshToken = jwt.sign(
          { userId: userId },
          process.env.JWT_KEY!,
          { expiresIn: "7d" }
        );
        const salt = bcrypt.genSaltSync(Number(process.env.SALT_ROUND!));
        const refreshToken = bcrypt.hashSync(RefreshToken, salt);
        //유저에 암호화된 리프레쉬 토큰 저장
        await User.update({refreshToken}, {where : {userId}})
        res.cookie("refreshToken", RefreshToken);
        res.cookie("accessToken", AccessToken);
        res.status(200).json({
          message: "로그인 성공",
          accesstoken: AccessToken,
          refreshtoken: RefreshToken,
        })
      }
    )(req, res, next);
  } catch (error) {
    next(error);
  }
};

구현된 로직이 실행되고 리이랙트하게된다. (아직 경로가 정해지지 않아 적지 않았다.)

코드 끝에 (req,res,next)를 쓰지않으면 미들웨어 오류가 나기 떄문에 꼭 적어주자.

'항해 99' 카테고리의 다른 글

항해 99 66일차 11/23일  (0) 2022.11.24
항해 99 65일차 11/22일  (0) 2022.11.23
항해 99 62일차 11/19일  (0) 2022.11.20
항해 99 61일차 11/18일  (0) 2022.11.19
항해 99 60일차 11/17일  (0) 2022.11.18