[인프런 워밍업 클럽 3기] 풀스택 과정 4주차 발자국 👣

[인프런 워밍업 클럽 3기] 풀스택 과정 4주차 발자국 👣

이번 주차에는 SupabaseAuth, Realtime, RLS를 사용해봤고, Next.js 팀에서 만든 배포 플랫폼인 Versel을 이용해 지금까지의 작업물을 배포해보았다!

 

imageimage

 

먼저 Auth를 살펴보자.

1. 회원가입

  • 무료 Supabase 프로젝트는 이메일 인증 기본 제공량이 1시간에 3통

    ⇒ SMTP 서버 직접 세팅하면 무제한 전송 가능

1. Confirmation URL 방식 - 메일의 인증 링크 클릭, 리다이렉트

supabase.authsignUp, exchangeCodeForSession, getSession을 이용 signUp 함수 optionsemailRedirectTo 값으로 exchangeCodeForSession을 실행할 페이지의 경로를 넘겨줌 경로 속 route.tsx 파일에서 exchangeCodeForSession 실행, redirect url의 code search param 값 이용해 세션을 얻어 로그인 처리 후, NextReseponse.redirect 이용해 기본 주소로 리다이렉트 처리 기본 주소에서 getSession 이용해 로그인 여부 확인, 상태에 맞는 화면(기본 화면 / 로그인(회원가입) 화면 중 하나) 보여주게 처리

메일 인증 링크 형식

https://{뭔가고유한문자열}.supabase.co/auth/v1/verify?token={tokenHash}&type=signup&redirect_to={리다이렉트url}

절차

  1. 메일의 ‘인증’ 버튼 클릭 시 위 링크로 이동하는데, 인증을 마친 뒤 {리다이렉트url}로 이동, code라는 searchParam과 함께 리다이렉트함

  2. Web client에서 code searchParam 값을 이용해 로그인 세션 획득, supabase.auth.exchangeCodeForSession 함수 이용해 로그인 처리

    • supabase.auth.signUp 함수에 options 값으로 넘긴 redirectUrl 경로에서 열릴 파일을 정의

      	options: {
          emailRedirectTo: "<http://localhost:3000/signup/confirm>", // 인증 완료 후 리다이렉트 url
      },
      
      • 위 경로의 경우, app/signup/confirm/route.tsx에 정의하면 됨

    • url과 일치하도록 폴더와 route.tsx 파일을 생성

      • Next.js 14 이상부터 사용되는 개념

      • API 정의 및 GET, POST, UPDATE 요청 등을 관장

      • 해당 url에 접속했을 때, 이 파일에 작성된 작업을 수행

        ex. GET을 정의 → GET 오퍼레이션을 날림

    // app/signup/confirm/route.tsx
    
    import { NextResponse } from "next/server";
    import { createServerSupabaseClient } from "utils/supabase/server";
    
    export async function GET(request: Request) {
        const requestUrl = new URL(request.url);
        // 이메일 인증 완료 후 redirect url에 'code' search param이 포함되어 돌아오게 됨
        const code = requestUrl.searchParams.get("code");
    
        if (code) {
            const supabase = await createServerSupabaseClient();
            // 'code' search param 값을 이용,
            // supabase auth에서 제공하는 exchangeCodeForSession 메서드를 사용하여
            // code를 이용해 로그인 세션 획득, 로그인 처리가 됨
            await supabase.auth.exchangeCodeForSession(code);
        }
    
        // redirect url로 이동 (localhost:3000/signup/confirm/?code=... -> localhost:3000/)
        return NextResponse.redirect(requestUrl.origin);
    }
    
  3. 코드 → 세션 교환해 로그인 처리 후 NextResponse.redirect를 호출해 리다이렉트 (기본 url로 가게 설계)

  4. 기본 url에서는 유저 로그인 상태를 체크해 상태에 맞는 페이지를 보여주도록 함

    // app/layout.tsx
    
    // async function RootLayout 안에서 (서버 컴포넌트여서 async function으로 정의 가능)
    const supabase = await createServerSupabaseClient();
    const {
        data: { session },
    } = await supabase.auth.getSession();
    const loggedIn = !!session?.user;
    
    // return문 안에서
    {loggedIn ? <MainLayout>{children}</MainLayout> : <Auth />}
    

layout.tsx:23 Server Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server.

2. 6자리 OTP 방식 - 메일의 6자리 OTP 토큰을 사용자가 복사해 인증 진행, OTP 입력 및 제출을 위한 인풋 UI 마련 필요

1번에서 구현한 이메일, 패스워드로 signUp하는 것은 동일, 그 사이에 verifyOtp 를 사용해 인증을 한번 거치는 것

mutationFn 작성

  • email, password만 넘겨줬던 signUp과 달리, type, email, token을 넘겨줘야 함

  • type은 “signup”

mutationFn: async ({ email, otp }: { email: string; otp: string }) => {
    const { data, error } = await supabase.auth.verifyOtp({
         type: "signup", // 왜 signup이지?
         email,
         token: otp,
    });

    if (error) {
        handleError(error);
    }

    return data;
},

회원가입 form에서, confirmationRequired 상태일 때 보여줄 <input /> 추가(otp 입력 받을 창)

  • otp용 useState, input 추가하고

  • onSubmit과 button에 otp 관련 상태 처리 코드 추가

3. 카카오로 로그인

Kakao Developers에서 선행 작업 필요

signInWithOAuth 함수 사용

  • 이 함수는, authentication에 없는 계정일 경우 새로 추가하고 아니면 다음 단계로 넘어가도록 설계가 되어 있나봄. 그래서 signin, signup에 별도로 구현할 필요 없이 이 함수 이용하는 동일한 하나의 로직을 이용하면 됨

  • provider에 “kakao”, optionsredirectTo 전달

  • authentication에는 Provider에 Kakao(1번 방법에선 Email)인 유저가 추가됨

route 정의 필요

  • 1번 방법과 마찬가지로, redirect url로 설정했던 경로와 일치하는 route.ts 파일을 추가

    • ex. app/auth/callback/route.ts

  • 마찬가지로 searchParams로 받은 code 값을 이용해 로그인 처리 가능 (exchangeCodeForSession)

2. 로그인

signInWithPassword로 간단히 구현 가능

return useMutation({
    mutationFn: async ({
        email,
        password,
    }: {
        email: string;
        password: string;
    }) => {
        const { data, error } = await supabase.auth.signInWithPassword({
            email,
            password,
        });

        if (error) {
            handleError(error);
        }

        return data;
    },
});

 

다음으로 Realtime도 살펴보자.

Broadcast - 직접 방출과 리슨을 구현하는 듯

  • 전체 공지를 보낼 때 등에 유용

  • 강력하지만 구현 복잡성이 높음

Presence - 현재 연결된 사용자를 실시간으로 추적. 유저가 들어왔다/나갔다를 파악 가능 (sync, join, leave)

  • 현재 온라인인 유저들 파악에 사용

  • 이 채널에 특정 유저가 있나 없나 확인 가능

  • 유저가 subscribe()하면 join으로, unsubscribe하면 leave로 인식됨

    • subscribe할 때 user의 onlineAt 같은 컬럼 값을 업데이트해줌으로써 유저가 언제 온라인이었는지 파악 가능하다?

  • sync는 join, leave 모두 감지 가능한, 말그대로 싱크가 맞춰져 있게 되는 것

    • 주로 sync를 사용하고, join, leave 발생 시 따로 노티를 띄워준다거나 하는 별도의 처리를 하고 싶을 때 join, leave를 사용하자

Postgres Changes - DB에 INSERT, UPDATE, DELETE 이벤트가 발생하는 것을 스트림

  • channel명을 정하고 subscribe하면 그 이후부터 db에 발생하는 이벤트를 리슨 가능

유용한 패키지

Javascript time ago

npm install --save javascript-time-ago

몇분전, 과 같은 문자열 표시를 돕는 패키지다. 로케일도 지원해 다국어를 지원해줘야 할 때 더 빛을 발한다.

 

그리고 RLS도 다뤄보았다.

RLS = Row Level Security

  • Low가 아니라 Row

  • 테이블의 Row 단위로 보안 규칙/제약을 설정할 수 있다는 의미

테이블 컬럼 수정

  • default value에는 함수 호출도 가능, auth.uid()는 로그인된 유저의 uid가 디폴트로 들어감!

    Can either be a literal or an expression. When using an expression wrap your expression in brackets, e.g. (gen_random_uuid()) - 함수 사용 시 ()까지 붙여 호출해주기

 

마지막으로 배포를 해보았는데, 깃허브 연동도 깔끔하게 되고 정말 매끄러운 배포 경험을 할 수 있었다.

Vercel이란

  • Next.js 만든 팀이 쉽게 배포할 수 있게 만든 플랫폼

  • 회원가입하고 github 연동해서 손쉽게 배포 가능

배포하기

배포 전 ide에서 npm run build 실행해 빌드 에러 없는지 먼저 체크하고,

거의 다 디폴트 값으로 따르면 되는데,

환경변수 값 넣어주기 - Environment Variables

.env 파일을 복사해서 붙여넣어주면 알아서 들어감

배포 전 실제 환경변수 값과 일치하는지 한번 더 체크하기!

환경변수 값이 잘못 들어가 500 에러가 발생했지만, 수정과 재배포가 간단해서 금방 수정할 수 있었다.

 

전역 상태관리 Jotai 사용

지난 주차에 전역 상태관리 툴 Recoil 버전 오류로 context api를 써서 갈음했었는데,

이번 주차 내용은 좀더 많은 전역 상태 관리가 필요해, 가벼운 라이브러리라는 Jotai를 사용해보았다.

정확히 어떤 원리로 동작하는지는 아직 뜯어보지 못했는데, 정말 간단하게 Provider를 만들어서 사용할 수 있었다.

타입도 명시하여 정의하는 방식이라 명확한 부분이 마음에 들었다.

사용법이 리코일보다도 간단해서 어떤 식으로 동작이 되는건지 살펴보고 싶다!

댓글을 작성해보세요.

채널톡 아이콘