inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

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

Yang HyeonBin
0

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

 

imageimage

 

먼저 Auth를 살펴보자.

1. 회원가입

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 작성

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 입력 받을 창)

3. 카카오로 로그인

Kakao Developers에서 선행 작업 필요

signInWithOAuth 함수 사용

route 정의 필요

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)

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

유용한 패키지

Javascript time ago

npm install --save javascript-time-ago

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

 

그리고 RLS도 다뤄보았다.

RLS = Row Level Security

테이블 컬럼 수정

 

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

Vercel이란

배포하기

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

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

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

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

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

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

 

전역 상태관리 Jotai 사용

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

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

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

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

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

답변 0