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
- 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 |
댓글