본문 바로가기
10. 클론코딩/>> 인스타그램

04 소셜로그인 인증하기

by 블록메타 2022. 12. 22.

4-1 NextAuth 설치

인증 구현 라이브러리는 NextAuth 입니다. NextJS에서 아주 쉽게 로그인을 구현할 수 있게 도와주는 라이브러리입니다.  

 

npm install next-auth

 

설치가 완료 되었으면 package.json을 살펴보겠습니다. 

 

package.json

{
 "private": true,
 "scripts": {
   "dev": "next dev",
   "build": "next build",
   "start": "next start"
 },
 "dependencies": {
   "@heroicons/react": "^1.0.6",
   "@tailwindcss/forms": "^0.5.3",
   "faker": "^6.6.6",
   "next": "latest",
   "next-auth": "^4.17.0",
   "react": "18.2.0",
   "react-dom": "18.2.0"
 },
 "devDependencies": {
   "@faker-js/faker": "^7.6.0",
   "@types/node": "18.11.3",
   "@types/react": "18.0.21",
   "@types/react-dom": "18.0.6",
   "autoprefixer": "^10.4.12",
   "postcss": "^8.4.18",
   "tailwindcss": "^3.2.1",
   "typescript": "4.8.4"
 }
}

next-auth버전이 4.17로 설치되었네요. 

 

4.2 [...nextauth].js 파일 설정하기

 

NextAuth 홈페이지에서 제공하는 소스를 그대로 복사해서 /pages/api/auth/[...nextauth].ts 파일을 만듭니다. 



NextAuth 제공하는 설정소스

/pages/api/auth/[...nextauth].js 에서 Apple, FaceBook, Google, Mail Server 여러개의 프로바이더를 지원하는 소스가 있습니다. 우리의 목표는 구글 인증만 사용하기 때문에 구글을 제외한 나머지는 삭제하였습니다. 

import NextAuth from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'

export default NextAuth({
 providers: [
   // OAuth authentication providers...
  
   GoogleProvider({
     clientId: process.env.GOOGLE_CLIENT_ID,
     clientSecret: process.env.GOOGLE_CLIENT_SECRET
   }),
 ],
 pages: {
   signIn: "/auth/signin",
 }
})

[...nextauth].js 파일은 NextAuth 설정 파일인데요. 

 

4.3  Firebase 

 

  1. Create a project 

프로젝트 이름은 instagram-clone으로 입력해 주세요. 

Google 애널리틱스 사용 설정은 uncheck 해 주세요.  

 

파이어베이스 프로젝트는 준비되었습니다. 

 

2. firebase 에서 Web app Create 



프로젝트설정 - 웹앱아이콘 클릭

웹앱 이름을 등록합니다. 우리는 instagram-clone-app 으로 하겠습니다. 

 

firebase를 인스톨

 

npm i firebase 



기본 제공하는 소스를 firebase.js 파일에 복사합니다. 

 

firebase.js

// Import the functions you need from the SDKs you need
import { getApp, getApps, initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";

// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries

// Your web app's Firebase configuration
const firebaseConfig = {
 apiKey: "AIzaSyBw8GUu--SwOUV_XocrBPx_IrXKnBss5Qc",
 authDomain: "instagram-clone-78f16.firebaseapp.com",
 projectId: "instagram-clone-78f16",
 storageBucket: "instagram-clone-78f16.appspot.com",
 messagingSenderId: "999590753819",
 appId: "1:999590753819:web:e78325bc7fa3451d2f6abe"
};

// Initialize Firebase
const app = !getApps().length ? initializeApp(firebaseConfig) : getApp();

const db = getFirestore();
const storage = getStorage();

export { app, db, storage };

 

3. Fire Authentication

 

 

웹 SDK구성을 클릭하면 웹클라이언트ID, 웹클라이언트보안비밀번호를 확인할 수 있습니다. 

 

4. env.local

 

웹클라이언트ID와 웹클라이언트 보안비밀번호는 안전하게 사용하기 위해 .env.local 파일에 넣어두세요. 

깃헙에는 보안을 위해서  .env.local 파일을 저장하지 않아야 됩니다. 

 

GOOGLE_CLIENT_ID=웹클라이언트ID

GOOGLE_CLIENT_SECRET=웹클라이언트 보안비밀번호

NEXTAUTH_URL=http://localhost:3000

 

5. 커스텀 signin 페이지 만들기

 

pages/api/auth/[...nextauth].js 파일에 signin 페이지 연결하기

import NextAuth from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'

export default NextAuth({
 providers: [
   // OAuth authentication providers...
  
   GoogleProvider({
     clientId: process.env.GOOGLE_ID,
     clientSecret: process.env.GOOGLE_SECRET
   }),
 ],
 pages: {
   signIn: "/auth/signin",
 }
})

pages/auth/signin.js 파일 만들기

 

import React from 'react'
import { getProviders, signIn } from "next-auth/react";

function signin({ providers }) {
 return (
   <>
       {Object.values(providers).map((provider) => (
           <div key={provider.name}>
               <button onClick={() => signIn(provider.id)}>
                   Sign in with {provider.name}
               </button>
           </div>
       ))}
   </>
 )
}

// Server Side Rendering
export async function getServerSideProps() {
   const providers = await getProviders();

   return {
       props: {
           providers
       }
   }
}

export default signin

6. Google Cloud Platform

 

instagram-clone 프로젝트로 선택하고 API 및 서비스 하위 사용자 인증 정보를 선택한다. 

 

OAuth 2.0 클라이언트 ID  Edit 버튼을 선택한다. 

 

승인된 자바스크립트 원본에 http://localhost:3000 입력하고, 승인된 리디렉션 URL에 http://localhost:3000/api/auth/callback/google 입력한다.

 

7. 세션 관리를 위해서 _app.js 수정하기

 

_app 파일은 페이지 전환시 레이아웃을 유지할 수 있습니다.  페이지 전환시 상태값도 유지 할 수 있습니다. componentDidCatch를 이용해서 커스텀 에러 핸들링을 할 수 있습니다. 추가적인 데이터를 페이지로 주입시켜주는게 가능합니다. 글로벌 CSS를 이곳에 선언합니다. 

 

_app.js

import { SessionProvider } from "next-auth/react";


function MyApp({ Component, pageProps: { session, ...pageProps } }) {
 return (
   <SessionProvider session={session}>
     <Component {...pageProps} />
   </SessionProvider>
 )
}

8. 로그인 후 유저 정보 출력하기

 

로그인 완료후에는 세션정보에서 유저 정보를 알 수 있다. 구글의 유저 정보의 이미지를 화면에 출력해 보자 

 

header.js 

import { useSession } from "next-auth/react";

function Header() {
   const { data: session } = useSession();


                     <img
                       className="w-7 h-7 rounded-full border p-[2px]"
                       src={session?.user?.image}
                   />

이제 세션정보 유무에 따라 메뉴도 다르게 출력할 수 있다. 

 

{ session ?  “로그인된메뉴” : “로그인 버튼” } 

 

header

{session ? (
                   <>
                      
                           <MenuIcon className="h-6 md:hidden cursor-pointer" />
                           <PaperAirplaneIcon className="navBtn " />
                           <PlusCircleIcon className="navBtn" />
                           <UserGroupIcon className="navBtn" />
                           <HeartIcon className="navBtn" />
                           <img
                               onClick={signOut}
                               className="w-10 h-10 rounded-full border p-[2px]"
                               src={session.user.image}
                           />
                      
                   </>

               ) : (
                   <button onClick={signIn}>Sign In</button>
               )}

signOut도 구현해 보자 

 

사용자 아이콘 이미지를 클릭시에 signOut을 호출해 보자. 

<img
   onClick={signOut}
   className="w-10 h-10 rounded-full border p-[2px]"
   src={session?.user?.image}
/>

로그아웃일때는 Sign In 버튼 표시 됩니다.

 

9. 로그인페이지 꾸미기

 

pages/auth/signin.js

function signin({ providers }) {
 return (
   <>
       <Header />
       <div className="flex flex-col items-center justify-center min-h-screen py-2 -mt-56 px-14 text-center">
           <img
               className="w-80"
               src='https://cdn.worldvectorlogo.com/logos/instagram-2.svg'
           />
           <div className="mt-40">
               {Object.values(providers).map((provider) => (
                   <div key={provider.name}>
                       <button
                           className="p-3 bg-blue-500 rounded-lg text-white"
                           onClick={() => SignIntoProvider(provider.id, { callbackUrl: '/' })}>
                           Sign in with {provider.name}
                       </button>
                   </div>
               ))}
           </div>
       </div>
   </>
 )
}

MiniProfile 유저 아이콘도 수정해 보자

function MiniProfile() {

 const { data: session } = useSession();

 return (
   <div className="flex items-center justify-between mt-14 ml-10">
       <img
           className="w-16 h-16 rounded-full border p-[2px]"
           src={session?.user?.image}
       />

       <div className="flex-1 mx-4">
           <h2 className="font-bold">{session?.user?.name}</h2>
           <h3 className="text-sm text-gray-400">Welcome to Instagram</h3>
       </div>
       <button
         onClick={signOut}
         className="text-blue-400 text-sm">Sign Out</button>
   </div>
 )
}

MiniProfile 과 Suggestions 컴퍼넌트는 로그인 되어 있을때만 표시하도록 수정해 보자

 

Feed

{/* Section */}
           {session && (
               <section className="hidden xl:inline-grid md:col-span-1">
                   <div className="fixed top-20">
                       <MiniProfile />
                       <Suggestions  suggestionUsers={randomUsers}/>
                   </div>
               </section>
           ) }

스토리에 제일 앞부분에 로그인한 아이콘도 표시하자

 

Stories

         {session && (
               <Story img={session.user.image}
                      username={session.user.name} />

           )}

 

home 아이콘에 ‘/’ 첫페이지로 링크 작업

 

next.js에서는 3가지 방법으로 링크 연결 할 수 있다. 

  • <a>  : 우리가 잘 알고 있는 html 링크, <a> 완전히 새로고침이 됩니다.  
  • <Link> 페이지를 다시 로드하지 않고 SPA동작처럼 보이게 만듭니다. 
  • Route push : window.location과 비슷하게 동작합니다. 검색엔진최적화(SEO) 되지 않습니다. 

 

필요에 따라서 3가지 중 사용하시면 됩니다.  여기서는 router.push를 사용했습니다. 

const router = useRouter();

<HomeIcon
   onClick={() => router.push('/')}
   className="navBtn " />

참고) router.push와 router.replace 차이

이전의 라우팅 히스토리를 모두 유지하고 싶으면 router.push를 사용, router.replace는 다른 url로 변경하고 싶을때, 히스토리에 남지 않음

 

'10. 클론코딩 > >> 인스타그램' 카테고리의 다른 글

05 Post 저장은 파이어베이스로  (0) 2022.12.22
03 시작하기  (0) 2022.12.21
02 환경설정  (0) 2022.12.21
01 Instagram 클론코딩 소개하기  (1) 2022.12.21

댓글