1. 기능 정의
1. 목적
- 사용자에게 카카오 로그인을 할 수 있게 함으로써 간편한 로그인을 제공한다.
2. 주요 기능 목록
- OAuth : Third Party 애플리케이션이 사용자의 리소스에 접근하기 위한 절차를 제공하고, 사용자 제공자의 API를 사용할 수 있도록 한다.
자세한 내용 : OAuth 2.0
2. 스펙 정의
1. 기술 스택
2. 상세 스펙
프로세스
- 카카오 인증 서버에 redirect uri, client id 등을 전달하여 로그인 페이지로 redirect시킨다.
- 사용자는 카카오 로그인을 한다.
- 카카오 인증 서버에서 브라우저를 redirect시킨다. 이 때, 인증 코드는 쿼리 스트링으로 발급된다.
- 쿼리스트링을 이용하여 카카오 인증 서버의 token 엔드포인트에 요청한다.
- Access Token을 발급 받는다.
- 이 Access Token을 저장한다.
- 이 Access Token으로 카카오 리소스 서버에 요청하여 사용자 정보(닉네임, 이미지)를 받아온다.
- 사용자의 닉네임과 이미지를 이용하여 댓글을 입력하고(DB 이용), 이를 보여준다.
고민 Point
- Refresh Token을 구현할 것인가?
- 인증 서버로부터 전달받은 Access Token을 통해 Refresh Token과 Access Token을 발급받는다
→ 백엔드 서버를 하나 띄어야할 것이다. ⇒ 2차 개발 때 진행해도 될 듯하다.
- 프론트엔드 서버 하나만으로 구현을 할 수 없을까?
- Next.js에는 Next.js Routes Handler를 제공하기에 DB에도 접근이 가능하다.
다른 사람들은 어떻게 구현했을까?
- gambit : Next.js Routes Handler + oracle DB
- 3개의 API가 존재한다.
- GET /api/guestbook : 방명록 목록 조회
- oracle DB에 접근하여 댓글 목록을 가져온다.
- GET /api/guestbook : 방명록 목록 조회
- 3개의 API가 존재한다.
코드
export const GET = async () => {
let connection: oracledb.Connection | null = null;
try {
connection = await oracledb.getConnection(dbConfig);
const { rows: guestbooks } = await connection.execute<GuestbookEntryType>(
queries.READ_ALL_GUESTBOOK,
[],
{
outFormat: oracledb.OUT_FORMAT_OBJECT,
}
);
return NextResponse.json(guestbooks);
} catch (e) {
return NextResponse.json(
{ message: (e as Error).message },
{ status: 500 }
);
} finally {
await closeConnection(connection);
}
};
queries : 각 쿼리들을 모아놓은 객체
- POST /api/guestbook : 방명록 작성
- oracle DB에 사용자가 댓글을 추가하면 이를 저장한다.
- email, name, image, body
코드
export const POST = async (req: NextRequest) => {
let connection: oracledb.Connection | null = null;
try {
const session = await getServerSession();
const { body } = await req.json();
if (!session) {
return NextResponse.json('Unauthorized', { status: 403 });
} else if (!body) {
return NextResponse.json('Body is required', { status: 400 });
}
const { email, name, image } = session.user as UserType;
connection = await oracledb.getConnection(dbConfig);
await connection.execute<GuestbookEntryType>(
queries.CREATE_GUESTBOOK,
[email, name, image, body],
{
outFormat: oracledb.OUT_FORMAT_OBJECT,
autoCommit: true,
}
);
return NextResponse.json('success');
} catch (e) {
return NextResponse.json(
{ message: (e as Error).message },
{ status: 500 }
);
} finally {
await closeConnection(connection);
}
};
- DELETE /api/guestbook/[id] : 방명록 제거
정리하면, oracle DB를 이용하여 방명록의 목록을 구현하였다. 그리고, 사용자의 정보는 getServerSession을 이용하여 불러왔다.
const session = await getServerSession();
// ..
const { email, name, image } = session.user as UserType;
getServerSession는 Next Auth에서 제공하는 함수이다.
또한, 토큰을 활용하지 않았다.
Next Auth는 알아서 필요한 사용자 정보를 받아온다.
uesSession 혹은 getServerSessions를 이용하면, 위 Process의 3번에서 7번까지는 생락햘 수 있다.
3. 개발 일정
- 시작일: 7/31
- 종료 예정일: 8/2
4. 개발
1. Kakao 로그인
-
내 애플리케이션 > 애플리케이션 추가하여 내 애플리케이션으로 이동한다.
-
앱 설정 > 앱 키 > Javascript 키 복사
주의 : REST API는 REST API를 이용하여 요청할 때 사용하는 것이고, 지금은 Javascript SDK를 이용한 호출이므로 Javascript 키를 복사한다.
이 값은 추후 client id가 될 것이다.
-
앱 설정 > 플랫폼 > Web에 사이트 도메인 등록
https://blog.guesung.site http://localhost:3000메인으로 사용할 도메인을 첫 번째, 개발 테스트용으로 사용할 도메인을 다음 줄에 적는다.
-
제품 설정 > 카카오 로그인에서 활성화 설정, Redirect URI 설정
Redirect URI는 반드시 위와 같은 형식을 따라야 한다. (참고)
-
제품 설정 > 동의 항목 설정
수집이 필요한 정보에 설정을 한다. 비활성화되어 있는 카카오 계정 이메일, 이름, 성별 등의 정보를 얻으려면 개인정보 동의항목 심사 신청을 해야 한다.
2. Next Auth 세팅
-
설치
pnpm add next-auth -
authOptions 생성
const authOptions: AuthOptions = { providers: [ KakaoProvider({ clientId: process.env.NEXTAUTH_KAKAO_CLIENT_ID || '', clientSecret: process.env.NEXTAUTH_KAKAO_CLIENT_SECRET || '', }), ], secret: process.env.NEXTAUTH_SECRET, }; export const nextAuth = NextAuth(authOptions);secret 생성 :
$ openssl rand -base64 32를 입력하여 무작위 키를 생성할 수 있다.providers에는 내가 사용할 플랫폼을 배열로 넘긴다.
-
로그인 : signIn
// .. return( <button onClick={() => signIn(provider)}>로그인</button> )provider에는 kakao, naver 등 로그인할 플랫폼명을 작성한다.
3. RSC에서 사용하는 방법
const session = await getServerSession(nextAuth)
4. RCC에서 사용하는 방법
Server에서 데이터를 미리 패칭하기 위해 RSC에서 데이터 패칭을 했다면, RCC에서 굳이 불러오는 경우는 거의 없을 것이다.
아래는 Next.js App Routing 기준이다.
// layout.tsx
// ..
return (
<SessionProvider>
<Component {...pageProps} />
</SessionProvider>
)
// RCC
const { data: session } = useSession()
RSC에서 SessionProvider에서 Server Component 관련한 에러가 뜬다면, Error: React Context is unavailable in Server Components 를 참고하길 바란다.
이제, 전달받은 session 데이터에는 사용자에 대한 정보가 있으니 활용하면 된다.