์ธ์ฆ ์ƒํƒœ์— ๋”ฐ๋ฅธ ํŽ˜์ด์ง€ ์ ‘๊ทผ ์ œํ•œ (Next.js, supabase)

2024. 7. 26. 03:10ยทissue

๋‹ค์Œ์€ ์ดˆ๊ธฐ์— ๋‚ด๊ฐ€ ๋ฐ”๋ž๋˜ ๊ธฐ๋Šฅ์ด๋‹ค.

 

- ๋กœ๊ทธ์ธ ์ƒํƒœ๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ ์ ‘๊ทผ ์ œํ•œ: /signin ์ด์™ธ์˜ ๋ชจ๋“  route

- ๋กœ๊ทธ์ธ ์ƒํƒœ์ผ ๊ฒฝ์šฐ ์ ‘๊ทผ ์ œํ•œ: /signin (๋กœ๊ทธ์ธ ์„ฑ๊ณต ์งํ›„ ์ด ํŽ˜์ด์ง€์—์„œ ๋ฒ—์–ด๋‚˜๋„๋ก.)

 

์‹ค์ œ ํŽ˜์ด์ง€์— ์ ‘๊ทผ ํ›„ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๊ฒŒ ๋˜๋ฉด ๋ถˆํ•„์š”ํ•œ ํ™”๋ฉด ์ด๋™์ด ์žˆ์„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ™”๋ฉด ๊นœ๋ฐ•์ž„๋„ ์ƒ๊ฒจ์„œ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์— ์ข‹์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํด๋ผ์ด์–ธํŠธ์—์„œ ํŽ˜์ด์ง€๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ณ  ์›ํ•˜๋Š” ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•  ๊ฒฝ์šฐ ์ž๊ฒฉ์ด ์—†๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ–ˆ์„ ๋•Œ ์ผ์‹œ์ ์œผ๋กœ ํ™”๋ฉด์ด ํ‘œ์‹œ๋œ ํ›„ ํŽ˜์ด์ง€๊ฐ€ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๋ฉด์„œ ๊นœ๋ฐ•๊ฑฐ๋ฆฐ๋‹ค.

 

Next.js ๋ฌธ์„œ๋ฅผ ๋’ค์ ธ๋ณด๋‹ˆ, middleware.ts ํŒŒ์ผ์—์„œ ์š”์ฒญํ•˜๋ฉด API ๋ผ์šฐํŠธ ๋˜๋Š” ํŽ˜์ด์ง€ ์š”์ฒญ ์ „์— ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณดํ˜ธํ•ด์•ผ ํ•  ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ดˆ๊ธฐ ์ ‘๊ทผ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ•œ๋‹ค. ๋‚˜๋Š” ์„ธ์…˜์„ ๊ฐ€์ ธ์™€์„œ middleware์—์„œ ์ฒดํฌ๋ฅผ ์ง„ํ–‰ํ–ˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์—์„œ ์„ธ์…˜์„ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ์€์ง€ ์ดํ›„ ๋ณด์•ˆ ๊ด€๋ จํ•ด์„œ ๋” ์ฐพ์•„๋ณด๊ณ  ์ˆ˜์ •ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

// ๋กœ๊ทธ์ธํ•ด์•ผ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฃจํŠธ[]
const protectedRoutes = ['/today', '/calendar']

export async function middleware(request: NextRequest) {
  const response = await updateSession(request)
  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: { 
    	/* ์ฟ ํ‚ค get/set/remove ์„ค์ • */
      },
    },
  )

  // session ๊ฐ’ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋ฆฌ๋‹ค์ด๋ ‰์…˜
  const { data: { session }, error} = await supabase.auth.getSession() 

  if (request.nextUrl.pathname === '/signin' && session) {
    url.pathname = '/'
    return NextResponse.redirect(url)
  }

  if (protectedRoutes.includes(request.nextUrl.pathname)) {
    if (!session) {
      url.pathname = '/signin'
      return NextResponse.redirect(url)
    }
  }
  if(error) {
    console.error(error)
  }
  return response
}

 

๊ทธ๋Ÿฐ๋ฐ ์œ„ ์ฝ”๋“œ๋ฅผ ์ ์šฉํ•œ ์ดํ›„ ๋ช‡๊ฐ€์ง€ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๋‹ค. 

  1. ๋กœ๊ทธ์ธ ์—†์ด ํŽ˜์ด์ง€์— ์ ‘๊ทผ๋งŒ ํ•ด๋„ ์„ธ์…˜ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ˜์†”์— ์„ธ์…˜ ์—†๋‹ค๊ณ  ๋œฌ๋‹ค.
  2. ์ผ๋ฐ˜ ๋กœ๊ทธ์ธ ์„ฑ๊ณต์‹œ '/' ๋กœ ์ด๋™ํ–ˆ์„ ๋•Œ ์„ธ์…˜๋งŒ ๋จผ์ € ์ฒดํฌํ•˜๊ณ  /๋กœ ์ด๋™ํ•ด์„œ, ์œ ์ €์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์™€ ์žˆ์ง€ ์•Š๊ณ  ์ƒˆ๋กœ๊ณ ์นจํ•ด์•ผ ๋“ค์–ด์˜จ๋‹ค. (task createํ•˜๋ ค๊ณ  ํ•˜๋ฉด user.id๊ฐ€ null์ด๋ผ๊ณ  ํƒœ์Šคํฌ ์ถ”๊ฐ€๊ฐ€ ์•ˆ๋œ๋‹ค.)
  3. OAuth ๋กœ๊ทธ์ธ ์„ฑ๊ณต์‹œ  '/signin'์„ ๋ฒ—์–ด๋‚˜์ง€ ์•Š๊ณ  '/signin'์— ๋‹ค์‹œ ๋Œ์•„์˜จ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์œ ์ € ๋ฐ์ดํ„ฐ๋Š” ๋“ค์–ด์™€ ์žˆ๋‹ค.

--- 

 

๐Ÿฅ• ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•! 

 

์ผ๋‹จ 1๋ฒˆ, 

 

๊ธฐ์กด์—๋Š” ์œ ์ €์˜ ๋ฐ์ดํ„ฐ๋ฅผ fetchํ•˜๋Š” ํ•จ์ˆ˜(fetchUser)๋งŒ ์žˆ์—ˆ๋Š”๋ฐ ์„ธ์…˜์„ ํ™•์ธํ•˜๊ณ  ์žˆ์œผ๋ฉด fetchUser๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ํ•˜๋Š” checkisLogin์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. (zustand ์‚ฌ์šฉ)

// @/store/useUserStore.ts

export const useUserStore = create<UserState>((set) => ({
   {/* user: null,*/}
  isLogin: false,
  {/* fetchUser, ๊ฐ™์Œ */}
  checkisLogin: async() => {
    const supabase = createClient()
    const {
      data: { session },
      error,
    } = await supabase.auth.getSession()
    if (error) {
      console.error('Check isLogin ERROR:', error)
    }
    if (session) {
      set({ isLogin: true })
      await useUserStore.getState().fetchUser()
    } else {
      set({ isLogin: false })
    }
  },
}))

 

 

2๋ฒˆ ์ผ๋ฐ˜ ๋กœ๊ทธ์ธ ์˜ค๋ฅ˜์—์„  ๊ธฐ์กด์—๋Š” response๋ฅผ ๋ฐ›์œผ๋ฉด await fetchUser() ํ•ด์™”๋Š”๋ฐ, 

 

๋กœ๊ทธ์ธ ์•ก์…˜ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์— ์—๋Ÿฌ๊ฐ€ ์—†์œผ๋ฉด checkisLogin()์„ ์‹คํ–‰ํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด์„œ ์ง„ํ–‰ํ–ˆ๋‹ค.

if (response && response.error) {
        alert('์ผ์น˜ํ•˜๋Š” ๊ณ„์ •์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”. ')
      } else {
        await checkisLogin() // ์š”๊ฑฐ
      }

 

      3๋ฒˆ OAuth ์˜ค๋ฅ˜

  ์ด๊ฑด ์—ฌ๋Ÿฌ๊ฐ€์ง€๋ฅผ ์ž˜๋ชปํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

    ์ผ๋‹จ ์ฒซ๋ฒˆ์งธ๋กœ OAuth์˜ ์•ก์…˜์„ ๋‹ด๋‹นํ•˜๋Š” ํŒŒ์ผ์˜ ๊ฒฝ๋กœ์™€ ํŒŒ์ผ๋ช…์„ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ์‚ฌ์šฉํ–ˆ๋˜ ์ .

 

๊ทธ๋ฆฌ๊ณ  ๋‘๋ฒˆ์งธ๋Š”  ํด๋ผ์ด์–ธํŠธ์ชฝ ์ฝ”๋“œ์—์„œ ๋ฒ„ํŠผ ํ•จ์ˆ˜์— ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๊ฒฝ๋กœ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•ด์•ผ ํ–ˆ๋Š”๋ฐ ๋นผ๋จน์–ด์„œ์˜€๋‹ค.

const handleGoogleLogin = async () => {
    const supabase = createClient()
    const { error } = await supabase.auth.signInWithOAuth({
      provider: 'google',
      options: {
        redirectTo: 'http://localhost:3000/auth/callback', // ์ด ๋ถ€๋ถ„์„ ์•ˆ ์“ฐ๊ณ  ์žˆ์—ˆ๊ณ , ๊ธฐ์กด์— ์‚ฌ์šฉํ•˜๋˜ ์•ก์…˜ ํ•จ์ˆ˜๋Š” ๊ฒฝ๋กœ๊ฐ€ ์ž˜๋ชป๋˜์–ด์„œ ์ ์šฉ์ด ์•ˆ๋˜๊ณ  ์žˆ์—ˆ๋‹ค
        queryParams: {
          access_type: 'offline',
          prompt: 'consent',
        },
      },
    })

 

Next.js + supabase๋กœ ์ž‘์—…ํ•˜๋˜ ๊ฑด๋ฐ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ-ํŒŒ์ผ๋ช…(/api/auth/...)๊นŒ์ง€ ์ง€์ผœ์•ผํ•œ๋‹ค๋Š” ์ƒ๊ฐ์„ ๋ชปํ–ˆ๋‹ค.

 

2๋ฒˆ 3๋ฒˆ ์˜ค๋ฅ˜๋Š” ์ง„์งœ ์Šคํ„ฐ๋”” ๊ธฐ๊ฐ„ ๋‚ด๋‚ด ์–ด๋””์„œ๋ถ€ํ„ฐ ์ž˜๋ชป๋œ๊ฑด์ง€ ๋ชจ๋ฅด๊ฒ ์–ด์„œ ๋จธ๋ฆฌ๋ฅผ ์‹ธ๋งธ๋Š”๋ฐ, ์Šคํ„ฐ๋”” ๋๋‚˜๊ณ  ๋‚˜์„œ๋ผ๋„ ์ฐพ์•„๋‚ด์„œ ๋‹คํ–‰์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค. Next ์‚ฌ์šฉํ•˜๋ฉด์„œ ๊ฒฝ๋กœ ์ง€์ •์ด๋ผ๋˜์ง€, ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ตฌ๋ถ„ํ•˜๋ฉด์„œ ์ž‘์„ฑํ•˜๋Š” ๊ณผ์ •์„ ํ†ตํ•ด ๋‘˜์„ ๋ถ„๋ฆฌํ•ด์„œ ์ƒ๊ฐํ•˜๋Š” ๋ฐฉ์‹์ด๋ผ๋˜์ง€ ๋งŽ์ด ๊ณต๋ถ€ํ–ˆ๋‹ค. ๊ทผ๋ฐ 15๊ฐ€ ๋‚˜์™”๋„ค....

'issue' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

ํšŒ์›๊ฐ€์ž…์‹œ ์ด๋ฉ”์ผ ์ธ์ฆ ๋ณด์•ˆ ์ด์Šˆ (api endpoint ๊ด€๋ จ)  (2) 2024.10.16
Git Error: RPC failed; HTTP 400 curl 22 The requested URL returned error: 400  (1) 2024.10.02
Date.toISOString() ๋กœ ์ธํ•œ -9์‹œ๊ฐ„ ๋˜๋Œ๋ฆฌ๊ธฐ (@date-fns)  (0) 2024.08.29
๋นŒ๋“œ ์ค‘ Module not found Error (Git)  (0) 2024.07.26
์†Œ์…œ ๋กœ๊ทธ์ธ ๊ด€๋ จ ์—๋Ÿฌ (OAuth flow error)  (0) 2024.07.26
'issue' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Git Error: RPC failed; HTTP 400 curl 22 The requested URL returned error: 400
  • Date.toISOString() ๋กœ ์ธํ•œ -9์‹œ๊ฐ„ ๋˜๋Œ๋ฆฌ๊ธฐ (@date-fns)
  • ๋นŒ๋“œ ์ค‘ Module not found Error (Git)
  • ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ด€๋ จ ์—๋Ÿฌ (OAuth flow error)
nuew
nuew
๐Ÿคธ ์žฌ์ฃผ ๋„˜๋Š” ์ค‘
  • nuew
    bloggg. . .๐Ÿฆ–๐Ÿ’ฅ
    nuew
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (88)
      • issue (10)
      • baekjoon (41)
      • lecture recap (11)
      • What I Learn (26)
      • retrospective (0)
      • maeil-mail (0)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    JavaScript
    js
    ๋ฐฑ์ค€
    TypeScript
    issue
    ํ•œ์ž…ํฌ๊ธฐ๋กœ์ž˜๋ผ๋จน๋Š”ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ
    css
    zustand
    media-query
    Node.js
    ์ฝ”๋”ฉํ…Œ์ŠคํŠธ
    Study
    ํ•œ์ž…ํฌ๊ธฐ๋กœ ์ž˜๋ผ๋จน๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ
    Baekjoon
    Algorithm
    ์•Œ๊ณ ๋ฆฌ์ฆ˜
    TailwindCSS
    modal
    what i learn
    ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
nuew
์ธ์ฆ ์ƒํƒœ์— ๋”ฐ๋ฅธ ํŽ˜์ด์ง€ ์ ‘๊ทผ ์ œํ•œ (Next.js, supabase)
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”