๐Ÿ”next-auth ์ธ์ฆ(authentication) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - useSession() (2)

์›ฐ์น˜์Šคยท2025๋…„ 1์›” 9์ผ

Next.js

๋ชฉ๋ก ๋ณด๊ธฐ
3/3

๐Ÿ“„ next-auth์˜useSession() ํ›…:

  • ํ˜„์žฌ ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ ์„ธ์…˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ์‚ฌ์šฉ๋จ

  • ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์„ธ์…˜ ์ •๋ณด๋ฅผ ์‰ฝ๊ฒŒ ์ ‘๊ทผํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

  • useSession() ํ›…์„ ์‚ฌ์šฉํ•  ๋•Œ SessionProvider ๋ฅผ ์ œ๋Œ€๋กœ ์„ค์ •ํ•ด์•ผํ•จ โฉ ์ผ๋ฐ˜์ ์œผ๋กœ app/layout.tsx ํŒŒ์ผ์—์„œ SessionProvider ๋ฅผ ์„ค์ •ํ•˜์—ฌ ๋ชจ๋“  ํŽ˜์ด์ง€์™€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ 

  • [...nextauth]/route.ts์—์„œ ์ธ์ฆ ์ •์˜ํ•ด์ค€ ํ›„ seSession()์„ค์ •

app/components/UserGreeting.tsx

'use client';

import { signOut, useSession } from "next-auth/react";
import { useRouter } from "next/navigation";


export default function UserGreeting() {
    // ์„ธ์…˜ ๊ฐ€์ ธ์˜ค๊ธฐ
    const { data : session, status} = useSession();

    const router = useRouter();
    const goToPage = (str: string) => {
        switch (str) {
            case 'signup': router.push('/signup'); break;
        }
    };


    // ์„ธ์…˜ ํ‘œ์‹œ
    if (status === 'loading') {
        return <span>Loading..</span>
    }

    if (session) {
        return (
            <div>
                <span>{session.user?.name} ์œผ๋กœ ๋กœ๊ทธ์ธ</span>
                <button className="btn btn-outline" 
          				onClick={() => signOut({ callbackUrl: '/'})}>
          			๋กœ๊ทธ์•„์›ƒ
  				</button>
            </div>
        );
    }

    return (
        <div>
            <button className="btn btn-outline" 
      				onClick={() => signIn()}>๋กœ๊ทธ์ธ</button>
            <button className="btn btn-outline" 
					onClick={() => goToPage('signup')}>ํšŒ์›๊ฐ€์ž…</button>
        </div>
    );
}

์„ธ์…˜ ์ƒํƒœ ๊ฐ’:

  • useSession() ํ›…์€ ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ๊ฐ’์„ ๋ฐ˜ํ™˜
    • session: ํ˜„์žฌ ์„ธ์…˜ ์ •๋ณด (null์ผ ์ˆ˜ ์žˆ์Œ).
    • status: ์„ธ์…˜ ์ƒํƒœ๋กœ 'loading', 'authenticated', 'unauthenticated' ์ค‘ ํ•˜๋‚˜.
  • ์„ธ์…˜ ์ƒํƒœ์— ๋”ฐ๋ฅธ UI ์ฒ˜๋ฆฌ:
    • status๊ฐ€ 'loading'์ด๋ฉด ๋กœ๋”ฉ ์ค‘์ž„์„ ํ‘œ์‹œ.
    • session์ด ์žˆ์œผ๋ฉด ์‚ฌ์šฉ์ž ์ •๋ณด์™€ ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์„ ํ‘œ์‹œ.
    • session์ด ์—†์œผ๋ฉด ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํ‘œ์‹œ.

์ถ”๊ฐ€ ์ •๋ณด

  • signIn ๋ฐ signOut ํ•จ์ˆ˜:
    • next-auth ํ•จ์ˆ˜์—์„œ ์ œ๊ณต๋˜๋Š” ํ•จ์ˆ˜
    • signIn(): ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๊ฑฐ๋‚˜ ํŒ์—…์„ ํ†ตํ•ด ๋กœ๊ทธ์ธ. [...nextauth]/route.ts ์˜ pages ์˜ต์…˜์—์„œ signIn๋กœ ์ •์˜ํ•œ ํŽ˜์ด์ง€๋กœ ์ด๋™
    • signOut(): ์‚ฌ์šฉ์ž๋ฅผ ๋กœ๊ทธ์•„์›ƒํ•œ ํ›„ signIn ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ. ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ•˜๋ ค๋ฉด callbackUrl ๋กœ ์ง€์ •ํ•˜์—ฌ ํ•  ์ˆ˜ ์žˆ์Œ

Custom Hooks:

  • ํ•„์š”ํ•œ ๊ฒฝ์šฐ useSession()์„ ํ™œ์šฉํ•˜์—ฌ ์ปค์Šคํ…€ ํ›…์„ ๋งŒ๋“ค์–ด ํŠน์ • ๋กœ์ง์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ ์šฉ

๐Ÿ’ญ ๋‚˜๋Š” ์ตœ์ƒ์œ„ ๋ ˆ์ด์•„์›ƒ์ธ `app/layout.tsx` ์—์„œ `SessionProvider`๋กœ ๋ชจ๋“  ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์ŒŒ๋‹ค. 
`app/layout.tsx` ์— ๋ฐ”๋กœ `SessionProvider` ๊ฐ์ŒŒ๋”๋‹ˆ `app/layout.tsx` ์— 
์ •์˜ํ•ด๋‘” `metadata` ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. 
`metadata` ๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ์‚ฌ์šฉ ํ•ด์•ผ ํ•˜๊ณ  `SessionProvider`๋Š” ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ
์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. `layout.tsx` ํŒŒ์ผ์—์„œ `metadata`์™€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถ„๋ฆฌํ–ˆ๋‹ค.
app/layout.tsx

import type { Metadata } from "next";
import localFont from "next/font/local";
import "./styles/globals.css";
import RootLayoutClient from "./RootLayoutClient";

const geistSans = localFont({
  src: "./fonts/GeistVF.woff",
  variable: "--font-geist-sans",
  weight: "100 900",
});
const geistMono = localFont({
  src: "./fonts/GeistMonoVF.woff",
  variable: "--font-geist-mono",
  weight: "100 900",
});

export const metadata: Metadata = {
  title: "Chicken Map",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
        <body
          className={`${geistSans.variable} ${geistMono.variable} antialiased`}
        >
          <RootLayoutClient>
            {children}
          </RootLayoutClient>
        </body>
    </html>
  );
}
app/RootLayoutClient.tsx

'use client';

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

export default function RootLayoutClient({
    children,
}: {
    children: React.ReactNode;
}) {
    return (
        <SessionProvider>
            {children}
        </SessionProvider>
    );
}

๋กœ๊ทธ์ธํ•˜๊ณ  ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋กœ ์„ธ์…˜ ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
Application ํƒญ > Storage > Cookies ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ

signOut() ํ•˜๋ฉด ์„ธ์…˜ ํ† ํฐ ๊ฐ’์€ ์‚ฌ๋ผ์ง„ ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค !

0๊ฐœ์˜ ๋Œ“๊ธ€