사용자가 간편하고 또한 개발에서 관리도 편한 로그인 방법인 Oauth2.0을 구현 해보자!
먼저 카카오 디벨로퍼에 가입하고 새로운 앱을 등록하는 과정입니다.
이렇게 하면 사전준비 완료입니다.
먼저 app/api/auth/[...nextauth]/route.ts에 kakao provider을 추가합니다.
import NextAuth from "next-auth/next";
import CredentialsProvider from "next-auth/providers/credentials";
import KakaoProvider from "next-auth/providers/kakao";
const handler = NextAuth({
providers: [
CredentialsProvider({
// The name to display on the sign in form (e.g. "Sign in with...")
name: "Credentials",
// `credentials` is used to generate a form on the sign in page.
// You can specify which fields should be submitted, by adding keys to the `credentials` object.
// e.g. domain, username, password, 2FA token, etc.
// You can pass any HTML attribute to the <input> tag through the object.
credentials: {
username: {
label: "이메일",
type: "text",
placeholder: "이메일 주소 입력 요망",
},
password: { label: "비밀번호", type: "password" },
},
async authorize(credentials, req) {
const res = await fetch(`${process.env.NEXTAUTH_URL}/api/login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: credentials?.username,
password: credentials?.password,
}),
});
const user = await res.json();
console.log(user);
if (user) {
// Any object returned will be saved in `user` property of the JWT
return user;
} else {
// If you return null then an error will be displayed advising the user to check their details.
return null;
// You can also Reject this callback with an Error thus the user will be sent to the error page with the error message as a query parameter
}
},
}),
KakaoProvider({
clientId: process.env.KAKAO_CLIENT_ID!,
clientSecret: process.env.KAKAO_CLIENT_SECRET!,
}),
],
callbacks: {
async jwt({ token, user }) {
return { ...token, ...user };
},
async session({ session, token }) {
session.user = token as any;
return session;
},
},
pages: {
signIn: "/signin",
},
});
export { handler as GET, handler as POST };
그럼 바로 로그인 처리가 완료됩니다.
이렇게 간단한 방법으로 로그인 처리를 완료했습니다.
물론 이전에 사용한 커스텀 로그인 페이지에 적용도 가능합니다.
app/signin/page.tsx
"use client";
import React, { useRef, useEffect, useState } from "react";
import { getProviders, signIn } from "next-auth/react";
function Login() {
// 추가된 부분
const [providers, setProviders] = useState(null);
useEffect(() => {
(async () => {
const res: any = await getProviders();
console.log(res);
setProviders(res);
})();
}, []);
// 추가된 부분
const emailRef = useRef(null);
const passwordRef = useRef(null);
const handleSubmit = async () => {
// console.log(emailRef.current);
// console.log(passwordRef.current);
const result = await signIn("credentials", {
username: emailRef.current,
password: passwordRef.current,
redirect: true,
callbackUrl: "/",
});
};
// 추가된 부분
const handleKakao = async () => {
const result = await signIn("kakao", {
redirect: true,
callbackUrl: "/",
});
};
// 추가된 부분
return (
<main className="flex min-h-screen flex-col items-center space-y-10 p-24">
<h1 className="text-4xl font-semibold">Login</h1>
<div>
<div>
<label
htmlFor="email"
className="block text-sm text-gray-800 dark:text-gray-200"
>
Email
</label>
<div className="mt-1">
<input
ref={emailRef}
onChange={(e: any) => {
emailRef.current = e.target.value;
}}
id="email"
name="email"
type="email"
required
autoFocus={true}
className="mt-2 block w-full rounded-md border bg-white px-4 py-2 text-gray-700 focus:border-blue-400 focus:outline-none focus:ring focus:ring-blue-300 focus:ring-opacity-40 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:focus:border-blue-300"
/>
</div>
</div>
<div className="mt-4">
<label
htmlFor="password"
className="block text-sm text-gray-800 dark:text-gray-200"
>
Password
</label>
<div className="mt-1">
<input
type="password"
id="password"
name="password"
ref={passwordRef}
onChange={(e: any) => (passwordRef.current = e.target.value)}
className="mt-2 block w-full rounded-md border bg-white px-4 py-2 text-gray-700 focus:border-blue-400 focus:outline-none focus:ring focus:ring-blue-300 focus:ring-opacity-40 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:focus:border-blue-300"
/>
</div>
</div>
<div className="mt-6">
<button
onClick={handleSubmit}
className="w-full transform rounded-md bg-gray-700 px-4 py-2 tracking-wide text-white transition-colors duration-200 hover:bg-gray-600 focus:bg-gray-600 focus:outline-none"
>
Log In
</button>
</div>
</div>
// 추가된 부분
<div>
<button
className="w-full transform rounded-md bg-gray-700 px-4 py-2 tracking-wide text-white transition-colors duration-200 hover:bg-gray-600 focus:bg-gray-600 focus:outline-none"
onClick={() => signIn("kakao", { redirect: true, callbackUrl: "/" })}
>
kakao login
</button>
</div>
// 추가된 부분
</main>
);
}
export default Login;
자 그럼 여기까지는 링크와 MongoDB를 연동해 진행한 부분이였습니다. 하지만 실제 서비스에 적용하기 위해서는
이것을 포함한 나머지 다양한 처리 부분을 이어가도록 하겠습니다.