https://lopunko.notion.site/Part-3-Supabase-Auth-1ba2621a1b5345f3b02d2059d47ac7a3
Supabase Auth
- Supabase Auth는 다양한 인증 방식을 지원하는 인증 시스템입니다.
- 사용자 인증 및 권한 관리를 제공합니다.
- 이메일 인증, Magic Link를 통한 비밀번호 없는 로그인, 전화번호를 통한 로그인, 소셜 로그인, 그리고 기업용 SSO 등 다양한 방법으로 사용자 인증을 지원합니다.
- 19가지 이상의 소셜 로그인 방식도 지원하며, Facebook, Google, GitHub, 카카오(Kakao), Slack 등의 서비스를 이용하여 로그인할 수 있습니다.
- 전화번호 인증은 Twilio 등의 외부 Provider를 사용하여 진행 가능합니다.
- 인증 방식은 JWT나 Session을 사용하여 설정할 수 있습니다.
- next.js를 사용하는 경우, 별도의 설정 문서를 통해 Supabase Auth 설정을 진행할 수 있습니다.
- Supabase Auth를 통해 웹사이트에 간편하게 사용자 인증 기능을 추가할 수 있습니다.
https://supabase.com/dashboard/project/eceptjznfdhgchrlzyyt/auth/users
1. 인증 링크로 회원가입
https://supabase.com/docs/guides/auth/passwords
https://lopunko.notion.site/Part-4-28ca1fc056bf4b3691b4e06caeac9384
supabase -> auth
site url -> 현재 웹사이트를 입력하면된다.
redirect URL -> 회원가입이나 인증과정을 완료됐을때 어느곳으로 리다이렉트 시킬지
Email template
( 무료 서비스는 1시간에 3번만 가능 )
.
confirmationURL 을 사용해서 이메일 인증을 할 수 있음
이렇게 하고 SAVE 누르면 세팅은 완료된거임
이제 회원가입 페이지에서 가입 구현을 하면됨
export default function SignUp({ setView }) {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmationRequired, setConfirmationRequired] = useState(false); //이메일 인증 완료 여부
//supabase auth
const supabase = createBrowserSupabaseClient();
//signup mutation
const signupMutation = useMutation({
mutationFn: async () => {
const { data, error } = await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: "http://localhost:3000/signup/confirm", //이메일 링크 클릭하여 , SUPABASE 회원가입 처리 된 후 리다이렉트되는 주소
},
});
if (data) {
setConfirmationRequired(true);
}
if (error) {
alert(error.message);
}
},
});
가입하기 버튼도 이미 가입하기 실행중 일 때는 한번 더 클릭하지 못하도록 코드를 수정한다.
<Button
onClick={() => signupMutation.mutate()}
loading={signupMutation.isPending}
disabled={confirmationRequired}
className="w-full text-md py-1 "
color="light-blue"
>
{confirmationRequired ? "메일함을 확인해주세요" : "가입하기"}
</Button>
</div>
이메일 인증 후 리다이렉트 주소는
http://localhost:3000/signup/confirm?code=....
으로 될거임
import { NextResponse } from "next/server";
import { createServerSupabaseClient } from "utils/supabase/server";
//localhost:3000/signup/confirm?code....
export async function GET(request: Request) {
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get("code");
if (code) {
const supabase = await createServerSupabaseClient();
await supabase.auth.exchangeCodeForSession(code); //코드가 정상적이면 세션을 획득함
}
//localhost:3000/ 으로 리다이렉트
return NextResponse.redirect(requestUrl.origin);
}
비밀번호 6자리 이상 입력해야함
가입하기를 클릭하면 입력한 메일로 인증 메일이 간다.
.
이렇게 메일이 온다 ..
인증하기를 클릭하면 유저추가가 된다.
하지만 이 상태에서는 현재 로그인의 여부는 확인할 수 없으므로
RootLayout에서 코드를 수정하여 확인해본다.
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const supabase = await createServerSupabaseClient();
const {
data: { session },
} = await supabase.auth.getSession();
console.log(session);
<ThemeProvider>
{session?.user ? <MainLayout>{children}</MainLayout> : <Auth />}
</ThemeProvider>
page.tsx 에서 유저 정보를 가져와서 표시할거임
이메일 전체를 가져오면 너무 길어지니까 split으로 분리하여 0번째만 가져옴
import LogoutButton from "components/auth/logout-button";
import { createServerSupabaseClient } from "utils/supabase/server";
export const metadata = {
title: "Inflearngram",
descripton: "Instargram clone project",
};
export default async function Home() {
const supabase = await createServerSupabaseClient();
const {
data: { session },
} = await supabase.auth.getSession();
return (
<main className="w-full h-screen flex gap-2 flex-col items-center justify-center">
<h1 className="font-bold text-xl">
{/* 유저 정보가져오기 */}
Welcome {session?.user?.email?.split("@"?.[0])}
</h1>
<LogoutButton />
</main>
);
}
로그아웃 버튼 컴포넌트에서 로그아웃 처리를 추가한다.
"use client";
import { Button } from "@material-tailwind/react";
import { createBrowserSupabaseClient } from "utils/supabase/client";
export default function LogoutButton() {
const supabase = createBrowserSupabaseClient();
return (
<Button
color="red"
onClick={async () => {
supabase.auth.signOut();
}}
>
로그아웃
</Button>
);
}
sidebar의 로그아웃 버튼에도 위의 코드를 그대로 넣어줌
{/* logout button */}
<div>
<button
onClick={async () => {
supabase.auth.signOut();
}}
>
<Logout className="text-2xl text-deep-purple-900" />
</button>
</div>
</aside>
auth-provider를 만든 후 적용
export default function AuthProvider({ accessToken, children }) {
const supabase = createBrowserSupabaseClient();
const router = useRouter();
useEffect(() => {
const {
data: { subscription: authListner },
} = supabase.auth.onAuthStateChange((event, session) => {
if (session?.access_token !== accessToken) {
router.refresh(); //리프레쉬
}
});
return () => {
authListner.unsubscribe(); //평소에는 구독을 하면서 새로고침을 시켜줬다가 화면이 닫히면 구독을 취소한다.
};
}, [accessToken, supabase, router]); //엑세스 토큰이 만료되었거나, 유저 로그아웃을 했다던가하면 리프레쉬한다.
return children;
}
<body className={inter.className}>
<RecoilProvider>
<ReactQueryClientProvider>
<ThemeProvider>
<AuthProvider accessToken={session?.access_token}>
{session?.user ? <MainLayout>{children}</MainLayout> : <Auth />}
</AuthProvider>
</ThemeProvider>
</ReactQueryClientProvider>
</RecoilProvider>
</body>