Supabase Auth 선택 이유 ✨
Supabase는 PostgreSQL을 사용해 데이터 정규화, 복잡한 쿼리 작업 등 SQL의 모든 기능을 사용할 수 있습니다. 그리고 요즘 떠오르는 기술이며 공식 문서 또한 너무 잘 되어 있기 때문에 적용하기 쉽다고 판단해서 선택하게 되었습니다.
사용 방법 📖
Authentication > Providers
Providers 탭으로 이동하면 다양한 로그인을 선택할 수 있습니다.
이메일을 이용해 간단한 로그인 구현과 OAuth를 이용한 소셜 로그인도 구현할 수 있습니다.
✨ Provider를 등록하는 방법은 공식 문서에 너무 잘 나와 있으니 생략하도록 하겠습니다.
Kakao
Authentication
Authentication > Users
사용자가 회원가입(이메일, SNS)을 하게 되면 `Users`라는 테이블에 해당 유저에 정보가 저장됩니다.
profiles 테이블 추가하기
Table Editor를 통해 `profiles`테이블을 생성해 주겠습니다.
속성으로 `id, user_name, email, avatar_url` 컬럼을 추가하고 `id`컬럼 타입은 uuid로 설정하겠습니다.
이후 auth.users 테이블 `uid`를 가져와 public.profiles의 `id`와 연결을 해줍니다.
Action은 해당 행이 지워지면 관계된 행도 같이 삭제할 수 있도록 Cascade로 선택하고 `Save`버튼을 눌러 저장합니다.
함수와 트리거 설정 📖
✨ 유저가 회원가입을 하고 `auth.users` 테이블에 새로운 행이 추가될 때 자동으로 `profiles`테이블에 해당 유저 정보를 추가하기 위해 설정합니다.
add_new_user() 함수 추가
`SQL Editor`에서 해당 함수를 작성해 줍니다.
create function public.add_new_user()
returns trigger as $$
begin
if new.raw_app_meta_data ->> 'provider' = 'email' then
insert into
public.profiles (id, email, user_name, avarta_url)
values
(
new.id,
new.email,
new.raw_user_meta_data ->> 'user_name',
new.raw_user_meta_data ->> 'avarta_url'
);
elsif new.raw_app_meta_data ->> 'provider' = 'kakao' then
insert into
public.profiles (id, email, user_name, avatar_url)
values
(
new.id,
new.email,
new.raw_user_meta_data ->> 'name',
new.raw_user_meta_data ->> 'avatar_url'
);
elsif new.raw_app_meta_data ->> 'provider' = 'google' then
insert into
public.profiles (id, email, user_name, avatar_url)
values
(
new.id,
new.email,
new.raw_user_meta_data ->> 'name',
new.raw_user_meta_data ->> 'avatar_url'
);
end if;
return new;
end;
$$ language plpgsql security definer;
이메일과 SNS로그인을 같이 사용했기 때문에 if문을 추가해서 provider별로 테이블의 데이터를 추가하는 sql을 다르게 설정해 주었습니다.
on_auth_user_created 트리거 추가
`auth.users` 테이블에 새로운 행이 추가되면 add_new_user() 함수를 실행해 `profiles` 테이블에 해당 유저 정보를 자동으로 추가해 줍니다.
create trigger on_auth_user_created
after insert on auth.users
for each row execute procedure public.add_new_user();
함수는 database탭에서 functions > schema:public에서 조회가 가능합니다.
트리거는 database탭에서 Triggers > schema:auth에서 조회가 가능합니다.
결과
이후 유저가 회원가입을 하게 되면 `profiles`테이블에 유저 정보가 잘 저장되는 걸 확인하실 수 있습니다.
로그인, 회원가입 하기 📖
기본 구성
❗Next.js에서 Supabase를 사용하기 위한 기본적인 설정 파일입니다.
utils > supabase > client.ts
import { createBrowserClient } from '@supabase/ssr';
export const createClient = () =>
createBrowserClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!);
const browserClient = createClient();
export default browserClient;
utils > supabase > server.ts
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
export const createClient = () => {
const cookieStore = cookies();
return createServerClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, {
cookies: {
getAll() {
return cookieStore.getAll();
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) => {
cookieStore.set(name, value, options);
});
} catch (error) {}
}
}
});
};
utils > supabase > middleware.ts
import { createServerClient } from '@supabase/ssr';
import { type NextRequest, NextResponse } from 'next/server';
export const updateSession = async (request: NextRequest) => {
try {
let response = NextResponse.next({
request: {
headers: request.headers
}
});
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value));
response = NextResponse.next({
request
});
cookiesToSet.forEach(({ name, value, options }) => response.cookies.set(name, value, options));
}
}
}
);
return response;
} catch (e) {
return NextResponse.next({
request: {
headers: request.headers
}
});
}
};
이메일 회원가입
const serverClient = createClient();
const {
data: { user },
error
} = await serverClient.auth.signUp({
email: userInfo.email,
password: userInfo.password,
options: {
data: {
user_name: userInfo.nickname
}
}
});
이메일로 회원가입을 진행할 때 email, password 외에 저장한 데이터는 options > data 객체에 넣어 요청을 보내면 `auth.users`테이블의 `raw_user_meta_data`에 저장됩니다.
SNS 회원가입
구글, 카카오 로그인 버튼을 누르게 되면 회원가입을 진행하게 됩니다.
`signInWithOAuth`함수를 부르게 되면 `redirectTo: window.origin + '/auth/callback'`으로 리다이렉션을 해서 origin으로 리다이렉션 될 수 있게 잡아주는 역할을 합니다.
❗이렇게 설정해주지 않으면 서버, 브라우저 클라이언트 간 연결이 매끄럽게 되지 않을 수 있습니다.
const signInWithSocial = async () => {
await browserClient.auth.signInWithOAuth({
provider: 'google or kakao',
options: {
redirectTo: window.origin + '/auth/callback'
}
});
};
app > auth > callback > route.ts에 라우터 핸들러를 구성해줍니다.
import { NextResponse } from 'next/server';
import { createClient } from '@/utils/supabase/server';
export const GET = async (request: Request) => {
const { searchParams, origin } = new URL(request.url);
const code = searchParams.get('code');
const next = searchParams.get('next') ?? '/';
if (code) {
const supabase = createClient();
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (!error) {
const forwardedHost = request.headers.get('x-forwarded-host');
const isLocalEnv = process.env.NODE_ENV === 'development';
if (isLocalEnv) {
return NextResponse.redirect(`${origin}${next}`);
} else if (forwardedHost) {
return NextResponse.redirect(`https://${forwardedHost}${next}`);
} else {
return NextResponse.redirect(`${origin}${next}`);
}
}
}
return NextResponse.redirect(`${origin}/auth/auth-code-error`);
};
이후 회원가입 및 로그인을 성공하게 되면 해당 유저 정보를 반환하게 되고 `auth.users`테이블의 `raw_user_meta_data`에 저장됩니다.
{
user: {
id: '',
aud: 'authenticated',
role: 'authenticated',
email: '',
email_confirmed_at: '2024-10-14T01:37:12.623212Z',
phone: '',
confirmed_at: '2024-10-14T01:37:12.623212Z',
last_sign_in_at: '2024-10-14T01:37:14.577923Z',
app_metadata: { provider: 'google OR kakao', providers: [ 'google OR kakao' ] },
user_metadata: {
avatar_url: '',
email: '',
email_verified: true,
full_name: '',
iss: 'https://kapi.kakao.com',
name: '',
phone_verified: false,
preferred_username: '',
provider_id: '',
sub: '',
user_name: ''
},
이렇게 이메일 로그인과 소셜 로그인을 구현하실 수 있습니다!
이슈❗
신규 사용자 추가 시 오류
출처 🏷️
'공부 > Next' 카테고리의 다른 글
Next 카카오맵을 활용한 시도별 가로 스크롤 버튼 이동 구현 (0) | 2024.10.28 |
---|---|
[리팩토링] Next 카카오 맵 폴리곤 렌더링 리팩토링 - 커스텀 훅, 유틸 함수 구조 개선 (0) | 2024.10.24 |
Next 카카오 맵 행정구역 나누기 (1) | 2024.10.23 |
Next 카카오 맵 구현 (0) | 2024.10.23 |
Next.js 알아보기 8 (Caching - 어려움 주의) (0) | 2024.09.27 |
Next.js 알아보기 7 (Route Handler & Server Action) (0) | 2024.09.26 |
Next.js 알아보기 6 (Asset 최적화) (2) | 2024.09.26 |
Next.js 알아보기 5 (Suspense, Loading, Error, Streaming SSR) (0) | 2024.09.26 |