Passport.js 를 이용한 구글 소셜 로그인 구현

rkdghwnd·2023년 6월 3일
0

구글 소셜 로그인 구현전 환경 설정

passport, cookie-parser, express-session 등의 설정은 로컬 로그인 참고

passport.js 이용한 구글 소셜 로그인 구현하기

구글 로그인 전략에 대한 공식문서

npm install passport-google-oauth20

구글 로그인 API 작성하기

routes/user.js

...
// 구글 로그인
router.get(
  "/google/auth",
  isNotLoggedIn,
  passport.authenticate("google", {
    scope: ["email"],
  })
);

router.get(
  "/google/callback",
  passport.authenticate("google", {
    failureRedirect: "/",
  }),
  function (req, res) {
    res.redirect(process.env.FRONT_END_DOMAIN);
  }
);
...

passport 구글 소셜 로그인은 두개의 API가 필요하다

  • 구글 서버로 인증요청을 보내는 API
  • 구글 서버로부터 인증정보를 받아 googleStrategy를 실행하는 API

googleStrategy 작성하기

passport/googleStrategy.js

const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const { User } = require("../models");
const dotenv = require("dotenv");
dotenv.config();

module.exports = () => {
  passport.use(
    new GoogleStrategy(
      {
        clientID: process.env.GOOGLE_CLIENT_ID,
        clientSecret: process.env.GOOGLE_CLIENT_SECRET,
        callbackURL: `${process.env.BACK_END_DOMAIN}/user/google/callback`,
        scope: ["profile", "email"],
        state: true,
      },
      async (accessToken, refreshToken, profile, done) => {
        console.log("google profile", profile);
        try {
          const exUser = await User.findOne({
            where: { snsId: profile.id, provider: "google" },
          });
          if (exUser) {
            done(null, exUser);
          } else {
            const newUser = await User.create({
              email: profile._json && profile._json.email,
              password: "",
              nickname: profile.emails[0].value,
              introduce: "",
              provider: "google",
              snsId: profile.id,
            });
            done(null, newUser);
          }
        } catch (error) {
          console.error(error);
          done(error);
        }
      }
    )
  );
};

공식문서 가이드를 바탕으로 googleStrategy를 작성한다

  • clientID : google developer console로 부터 발급받은 client ID
  • clientSecret : facebook developers로 부터 발급받은 google 보안 비밀번호
  • callbackURL: 구글 서버에서 인증정보를 보낼 Redirect URI
  • scope: 구글에서 받아올 계정정보
  • state: true로 설정하면 nonce를 생성하고 세션에 유지한다.
    Redirect URI 라우터에서 세번째 콜백함수 안에 req.authInfo.state의 형태로 사용가능
    세션값과 nonce의 값을 비교해서 일치하지 않을때 요청을 거부시킬수 있습니다.
    CSRF 공격을 방지하므로 사용하는것이 좋다. 참고
app.get('/auth/google/callback', 
  passport.authenticate('google', { failureRedirect: '/login' }), 
  function(req, res) { 
    var state = req.authInfo.state; 
    // 재개 상태... 
  });

구글 로그인 버튼 만들기

구글 로그인 버튼은 href 를 이용해 만들어야 정상적으로 작동한다.

	 <a href={`${process.env.NEXT_PUBLIC_BACK_END_DOMAIN}/user/google/auth`}>
        <img
          src={`${process.env.NEXT_PUBLIC_FRONT_END_DOMAIN}/images/google-auth-image.png`}
        ></img>
      </a>

google developer console에 내 앱 등록하기

google에 로그인한 후 google developer console에 접속해 프로젝트를 생성한다.

좌측메뉴에 OAuth 동의 화면 클릭
사용자 유형 외부로 되어있는지 확인

좌측메뉴 사용자 인증 정보 클릭
브라우저 URI, 리디렉션 URI를 등록한다.

구글 로그인 전체적인 실행 흐름

  1. 클라이언트에서 로그인 요청을 보낸다.
  2. 백엔드서버는 라우터로 요청을 받아 구글 서버로 인증 요청을 보낸다.(passport.authenticate("google"))
  3. 구글 서버는 클라이언트로 구글 로그인 요청을 보낸다.
  4. 사용자가 구글 로그인을 하며 구글 서버에서 인증처리를 한다.(req.login()을 구글 서버에서 처리)
  5. 구글 서버는 Redirect URI로 인증정보(계정정보)를 포함한 요청을 보낸다.
  6. 백엔드 서버가 라우터로 요청을 받으면 passport.authenticate("google")를 통해 googleStrategy르 실행한다.
  7. 인증정보를 바탕으로 DB조회를 한다.
  8. 이미 존재하는 사용자가 바로 done()으로 넘기고 아니면 DB에 등록후 done()으로 넘긴다.
  9. 전략 성공/실패에 따라 설정된 곳으로 세션쿠키와 함게 리다이렉트 한다.
profile
rkdghwnd's dev story

0개의 댓글