본문 바로가기

Frontend Dev/Supabase

supabase auth와 나의 public 테이블 연동하기 (회원가입시 auth의 유저 정보를 public 테이블로 가져오는 방법)

반응형

 ✏️ 이 글은 사이드프로젝트 "스무디"를 개발하며 알게된 점은 정리하여 기록한 글입니다. 

 

 

 

 

"스무디"는 firebase의 강력한 대체제라고 불리는 supabase를 사용하여 백엔드 코드를 작성할 필요 없이 serverless로 구현했다. supabase는 이번에 처음 사용해봤지만, 공식문서가 너무나 친절하게 잘 되어있어 어렵지 않고 빠르게 적용할 수 있었다. (firebase를 찍먹했을 때는 공식문서가 친절하다는 인상은 받지못했었던 것 같다.)

 

물론 대체적으로 어렵지 않았고, 필요하다 생각된 기능들은 거의 다 구현이 가능했지만 원하는 기능의 적용을 위해 헤맸던 부분도 꽤 있었다. 이번에는 그 중 하나였던 supabase auth와 나의 public 테이블을 연동하는 방법에 대해 기록해보겠다.

 

🔗 공식문서 출처 User Management | Supabase Docs

 

들어가기 전, 해당 기능이 필요했던 이유

새로운 유저가 회원가입을 하면 supabase의 auth.users 테이블에는 새로운 유저가 추가된다. 새로운 유저가 추가됨과 동시에 나의 public.profiles 테이블에 해당 유저의 정보를 저장하고 싶었다.

(auth.users는 supabase에서 관리하는 테이블, public은 내가 만든 테이블을 가지고 있다.)

왜냐하면 auth.users 테이블은 이미 정해진 구조가 있었기 때문에, 내가 담고 싶었던 유저 프로필에 대한 정보를 담을 수가 없었다. 예를 들면 mypage에서는 유저에 대한 다양한 정보들이 필요한데, 이런 정보를 담기 위해서는 커스텀 테이블이 필요했기 때문이다.

 

스무디의 mypage

 

따라서 회원가입시 supabase auth.users 테이블에서 필요한 유저 정보를 public.profiles 테이블로 가져와 저장할 수 있도록 구현해 보았다.

 

1. 회원가입시 필요한 metadata를 추가하고, 저장하자.

supabase auth에서 새로운 유저가 회원가입을 하기 위해서는 email, password를 받고, 회원가입시 추가적인 metadata를 options을 통해 할당할 수 있다.

const { data, error } = await supabase.auth.signUp({
  email,
  password,
  options: {
    data: {
      user_name: username,
      avatar_url: "",
    },
  },
})
// 회원가입 버튼 클릭
const onSubmit: SubmitHandler<SignupDataType> = data => {
  if (window.confirm(`${data.email}로 회원가입 하시겠습니까?`)) {
    const reqData = {
      email: data.email,
      password: data.password,
      username: data.username,
    };
    dispatch(signUpNewUser(reqData))
      // ... 생략
  }
};

 

➡️ options.data의 user_name은 회원가입시 입력한 username 값을 받아온다.

이렇게 추가된 user metadata는 auth.users 테이블의 raw_user_meta_data에 저장된다.

users의 user info

 

*참고로, avatar_url은 우선 빈문자열로 지정한다. 이번 프로젝트에서는 소셜 로그인 중 github 로그인만 구현했는데, github 로그인시 회원정보의 avatar_urlraw_user_meta_data.avatar_url 값으로 들어간다. 프로필 사진 표시를 위한 값인데, 일반 로그인시 프로필 사진을 수정하는 부분은 아직 구현하지 않았다.

 

2. profiles 테이블을 생성하고, 회원가입시 profiles 테이블을 업데이트 하도록 trigger function을 작성하자.

-- 1. create profiles table
create table
  public.profiles (
    id uuid not null,
    email text not null,
    user_name text not null,
    avatar_url text null,
    created_at timestamp with time zone default current_timestamp,
    modified_at timestamp with time zone default current_timestamp,
    cover_letter text null,
    tech_tags text[] null,
    hard_skills text[] null,
    soft_skills text[] null,
    projects text[] null,
    constraint profiles_pkey primary key (id),
    constraint profiles_id_fkey foreign key (id) references auth.users (id) on delete cascade
  ) tablespace pg_default;

-- 2. inserts a row into public.profiles
create function public.handle_new_user()
returns trigger
language plpgsql
security definer set search_path = public
as $$
begin
  insert into public.profiles (id, email, user_name, avatar_url)
  values (new.id, new.email, new.raw_user_meta_data ->> 'user_name', new.raw_user_meta_data ->> 'avatar_url');
  return new;
end;
$$;

-- 3. trigger the function every time a user is created
create trigger on_auth_user_created
  after insert on auth.users
  for each row execute procedure public.handle_new_user();
-- 잘못 생성되었을 경우 취소
drop function handle_new_user() cascade;


SQL문은 잘 몰라서 공식문서를 참고하여 작성된 코드이다.

 

1. profiles 테이블을 생성 (profiles.id는 auth.users.id와 foreign key로 묶어줘야 한다.)

2. public.profiles에 새로운 row를 추가하는 handle_new_user 함수 생성

3. 새로운 유저가 생성되면 handle_new_user 함수 트리거

 

이렇게 하면 새로운 유저가 생성되었을 때, public.profiles의 테이블이 업데이트 된다.

예를들어, “스무디”에서 새로운 유저가 회원가입을 할 때는 email, username, password를 기입해야 한다. 회원가입 버튼을 클릭하면 auth.users 테이블의 raw_user_meta_dataid = uuid, email = email, user_name = username, avatar_url = ””이 저장되고, public.profiles의 id, email, user_name, avatar_url은 새 유저(new)의 id, email, user_name, avatar_url을 받아온다.

(만약 트리거가 실패되면, 회원가입이 차단될 수 있으니 코드를 철저히 테스트하라고 한다.)

 

이렇게 해서 새로운 유저가 회원가입을 할 때 profiles 테이블을 자동으로 업데이트 하여 mypage에서 유저 정보를 사용할 수 있게 되었다!

 

👏🏻

 

반응형