[문제해결] 소셜로그인

dano Lee·2024년 5월 9일
0

트러블 핸들링

목록 보기
5/5

문제상황

  1. next-auth를 사용하여 구현한 소셜로그인이 로드벨런싱이 적용된 AWS 환경에서 리다이렉트 처리가 되지 않는 문제 발생
  2. 프론트단에서 소셜로그인에 따라 (인가코드 발급 -> 로그인 토큰 요청 -> 사용자 정보 요청) 방식으로 SSR을 사용하여 리다이렉트 페이지 구현

SSR 인가코드 발급 -> 로그인 토큰 요청 -> 사용자 프로필 조회 -> 유틸 함수로 분기처리 및 props 리턴 -> /auth/(google,naver,kakao).tsx 파일에서 SSR로 리턴되는 props 사용 -> 유틸 함수 실행 -> 홈 리다이렉트

1. 인가코드 발급 로그인창 요청 -> 소셜 로그인

// 요청 URL의 상세 파라미터값은 공식문서를 참고해보길 바란다.

// 구글로그인 요청 URL은 https://accounts.google.com/o/oauth2/v2/auth 이다.  
const googleAuthURL = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID}&redirect_uri=${process.env.NEXT_PUBLIC_REDIRECT_URL}/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile`;
window.location.href = googleAuthURL;

// 네이버로그인 요청 URL은 https://nid.naver.com/oauth2.0/authorize 이다.
const naverAuthURL = `https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=${process.env.NEXT_PUBLIC_NAVER_CLIENT_ID}&redirect_uri=${process.env.NEXT_PUBLIC_REDIRECT_URL}/naver&state=1234`;
window.location.href = naverAuthURL;

// 카카오 로그인 요청 URL은 https://kauth.kakao.com/oauth/authorize 이다.
const kakaoAuthURL = `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${process.env.NEXT_PUBLIC_KAKAO_CLIENT_ID}&redirect_uri=${process.env.NEXT_PUBLIC_REDIRECT_URL}/kakao`;
window.location.href = kakaoAuthURL;

2.로그인 완료 -> SSR 로그인 엑세스 토큰 요청 -> 사용자 정보 조회

const getServerSideProps = ({ query }) => {
  // query 값
  {
    code: 'testestestestestest', // 발급받은 인가코드
    scope: 'email profile' // 범위,
    authuser: '0',
    prompt: 'none'
  }

  // 로그인 엑세스 토큰 요청
  const getLoginToken = await axios({
    method: 'POST',
    url: 'https://oauth2.googleapis.com/token',
    data: {
      grant_type: 'authorization_code', // 인증 구분 값
      client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID, // 개발자센터에서 발급받은 클라이언트 아이디
      client_secret: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_SECRET, // 개발자센터에서 발급받은 CLIENT_SECRET
      redirect_uri: `${process.env.NEXT_PUBLIC_REDIRECT_URL}/google`, // 리다이렉트 URL 프론트 지정
      code: query.code, // 발급받은 인가코드 넣어주기
    },
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded', // 필수 값
    },
  });
  
  // 소셜 사용자 정보 조회
  const getProfile = await axios({
    method: 'GET',
    url: 'https://www.googleapis.com/oauth2/v3/userinfo',
    params: {
      access_token: getLoginToken.data.access_token,
    },
  });
}

3.유틸 함수 분기처리 및 SSR 프롭스 리턴

// 이 함수 또한 getServerSideProps에 포함되어 있다.
// 프로파일이 있을경우로 분기를 나누었다.
	if (getProfile) {
      return await socialLogin('GOOGLE', getLoginToken.data, getProfile.data);
    } else {
      return loginRedirect('프로필 정보를 가져오지 못했습니다. 로그인페이지로 이동합니다.');
    }
// 첫 번째 인자인 _provider 인자로 소셜 타입을 확인하여 이메일을 필터링한다.
// 두 번째 인자인 _tokenInfo 객체의 속성값인 access_token를 리턴해준다.
export const socialLogin = (_provider: string, _tokenInfo: any, _profileInfo: any) => {
  const filterSocialEmail =
    _provider === 'NAVER'
      ? _profileInfo.response.email
      : _provider === 'KAKAO'
      ? _profileInfo.kakao_account.email
      : _provider === 'GOOGLE' || _provider === 'FACEBOOK'
      ? _profileInfo.email
      : '';
  return {
    props: {
      userEmail: filterSocialEmail, // 소셜 타입에 따른 이메일
      access_token: _tokenInfo.access_token, // 로그인 엑세스 토큰
    },
  };
};

4./auth/(google,naver,kakao).tsx 파일 -> SSR 프롭스 사용 -> 리다이렉트 함수 실행


// SSR을 제외한 리다이렉트 컴포넌트의 코드이다.
const GoogleRedirectPage: NextPage = ({ userEmail, access_token }) => {
  useSocialLoginRedirect('google', userEmail, access_token);
  return <></>;
};

export default GoogleRedirectPage;

// useSocialLoginRedirect === 여러 컴포넌트에서 사용 가능하게 리액트 훅으로 사용하였다.
// useRouter를 함수의 인자로 넘겨주는 이유는 SSR 구성이라 useRouter를 ts 스크립트단에서는 사용하지 못하기 때문이다.
const useSocialLoginRedirect = (_provider: string, _userEmail: string, _access_token: string) => {
  const router = useRouter();

  useEffect(() => {
    if (_provider !== undefined && _userEmail !== undefined && _access_token !== undefined) {
      homeRedirect(router, _provider, _access_token);
    }
  }, [_provider, _userEmail, _access_token]);

  return <></>;
};

export default useSocialLoginRedirect;

// 해당 함수가 ts 파일에 있기 때문에 useRouter를 인자로 받아온다.
export const homeRedirect = (_router: NextRouter, _provider: string, _access_token: string) => {

  // 엑세스토큰 여부에 따라 router.replace로 홈 리다이렉트
  if (_access_token !== '') {
    const expires = dayjs().add(30, 'days').toDate();
    setCookie('provider', _provider, { expires, path: '/' }); // 유효기간 설정 소셜 타입 저장
    setCookie('sns_access_token', _access_token, { expires, path: '/' }); // 유효기간 설정 토큰 저장
    _router.replace('/'); 
  } else {
    console.log('소셜로그인 실패');
  }
};

요약 정리

  • 예시는 모두 구글로 되어 있지만 방식에는 차이가 없기 때문에 소셜 타입만 바꿔주면 된다.
  1. 로그인 창 요청 -> 인가코드 발급
  2. 각 소셜로그인 개발자 센터에 등록된 리다이렉트 URL로 이동 ( /pages/auth/( google,naver,kakao ) )
  3. SSR로 인가코드 받아와 로그인 토큰, 사용자 프로필 조회
  4. 리다이렉트 유틸 함수 리턴 -> 엑세스 토큰 여부에 따라 홈 또는 로그인 페이지로 이동
profile
세상에 이로운 영향력을 퍼뜨리고 싶은 프론트엔드 개발자 입니다.

0개의 댓글