Joonas' Note
[FastAPI + React] 소셜 로그인 구현하기 - 커스텀 로그인 (feat. 카카오) 본문
아래의 글을 먼저 읽고 진행하시는 것을 추천한다.
[FastAPI + React] 소셜 로그인 구현하기 - 구글 로그인
아래 글에서 이어지는 내용입니다. [FastAPI + React] 소셜 로그인 구현하기 - 이메일 로그인 아래 글에서 이어지는 내용이다. [FastAPI + React] 소셜 로그인 구현하기 - 기본 환경 구축 들어가기 전에 Reac
blog.joonas.io
들어가기 전에
Google, GitHub, Microsoft 등은 FastAPI Users에서 친절하게 구현을 미리 해주었습니다. 하지만 카카오와 같은 국내 기업들에 대한 로그인은 구현되어 있지 않다.
그래서 이 글에서는 클래스를 오버라이딩해서, 기존에 작성한 FastAPI Users와 완전히 호환되는 로그인을 구현한다.
FastAPI
커스텀 클라이언트 클래스
구글 로그인을 연동할 때에는, 아래와 같이 GoogleOAuth2 라는 클래스를 사용했었다.
from httpx_oauth.clients.google import GoogleOAuth2
google_oauth_client = GoogleOAuth2(
client_id=Configs.GOOGLE_CLIENT_ID,
client_secret=Configs.GOOGLE_CLIENT_SECRET,
scope=[
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email",
"openid"
],
)
이것과 동일하게 KakaoOAuth2 라는 클래스를 만들어서, Client ID와 Client Secret, 그리고 scope를 넘기면 유저 생성부터 기존 아이디 연동까지, FastAPI Users 에 그대로 호환되도록 한다.
아래와 같이 클래스를 만든다.
from typing import Any, Dict, List, Optional, Tuple, cast
import json
from httpx_oauth.errors import GetIdEmailError
from httpx_oauth.oauth2 import BaseOAuth2
from httpx_oauth.typing import TypedDict
AUTHORIZE_ENDPOINT = "https://kauth.kakao.com/oauth/authorize"
ACCESS_TOKEN_ENDPOINT = "https://kauth.kakao.com/oauth/token"
PROFILE_ENDPOINT = "https://kapi.kakao.com/v2/user/me"
BASE_SCOPES = ["account_email"]
BASE_PROFILE_SCOPES = ["kakao_account.email"]
class KakaoOAuth2(BaseOAuth2[Dict[str, Any]]):
display_name = "Kakao"
logo_svg = LOGO_SVG
def __init__(
self,
client_id: str,
client_secret: str,
scopes: Optional[List[str]] = BASE_SCOPES,
name: str = "kakao",
):
super().__init__(
client_id,
client_secret,
AUTHORIZE_ENDPOINT,
ACCESS_TOKEN_ENDPOINT,
name=name,
base_scopes=scopes,
)
async def get_id_email(self, token: str) -> Tuple[str, Optional[str]]:
async with self.get_httpx_client() as client:
response = await client.post(
PROFILE_ENDPOINT,
params={"property_keys": json.dumps(BASE_PROFILE_SCOPES)},
headers={**self.request_headers,
"Authorization": f"Bearer {token}"},
)
if response.status_code >= 400:
raise GetIdEmailError(response.json())
account_info = cast(Dict[str, Any], response.json())
kakao_account = account_info.get('kakao_account')
return str(account_info.get('id')), kakao_account.get('email')
주의할 점은, 카카오 API에서는 계정 id를 정수형으로 반환하는데, get_id_email 함수에서는 DB에서 조회할 때 이 타입이 달라서 검색을 하지 못하고 계속 새로운 계정을 생성한다. 그렇기 때문에 문자열로 변환해서 리턴해야 한다.
라우터 추가
이렇게 만든 클래스를 사용해서 구글 로그인과 동일하게 아래와 같이 라우터를 만들어서 추가한다.
auth_backend_kakao = AuthenticationBackend(
name="jwt-kakao",
transport=bearer_transport,
get_strategy=get_jwt_strategy
)
# 인증 클라이언트
kakao_oauth_client = KakaoOAuth2(
client_id=Configs.KAKAO_CLIENT_ID,
client_secret=Configs.KAKAO_CLIENT_SECRET,
scopes=[
# https://developers.kakao.com/docs/latest/ko/kakaologin/common#user-info-kakao-account
"profile_nickname", "profile_image", "account_email",
]
)
# 카카오 로그인 JWT 라우터
kakao_oauth_router = fastapi_users.get_oauth_router(
oauth_client=kakao_oauth_client,
backend=auth_backend_kakao,
state_secret=Configs.SECRET_KEY,
redirect_url="http://localhost:3000/login/kakao",
associate_by_email=True,
)
# 라우터 추가
app.include_router(kakao_oauth_router, prefix="/auth/kakao", tags=["auth"])
이제 Interactive docs에서 엔드포인트를 확인해보면 잘 추가된 것을 볼 수 있다.
React
리액트쪽에서 해줄 것은 구글 로그인과 동일하게 콜백에 대한 처리를 하는 부분밖에 없다.
<Route path="/login">
<Route index element={<Auth.Login />} />
<Route path="google" element={<Auth.Redirects.Google />} />
<Route path="github" element={<Auth.Redirects.Github />} />
<Route path="kakao" element={<Auth.Redirects.Kakao />} />
</Route>
엔드 포인트의 형식이 다른 로그인과 동일하기 때문에, /auth/kakao/callback 로 데이터를 그대로 전달해서 토큰을 발급받으면 된다.
customAxios()
.get("/auth/kakao/callback" + location.search)
.then(({ data }) => {
// 토큰 받아서 로그인 처리
login({
token: data.access_token,
});
})
.catch(({ response }) => {
console.error(response);
// 에러 처리
});
결과
코드
https://github.com/joonas-yoon/fastapi-react-oauth2/tree/signin-with-kakao
GitHub - joonas-yoon/fastapi-react-oauth2: FastAPI + MongoDB with Beanie + React Login Example
FastAPI + MongoDB with Beanie + React Login Example - GitHub - joonas-yoon/fastapi-react-oauth2: FastAPI + MongoDB with Beanie + React Login Example
github.com
'개발' 카테고리의 다른 글
SOLID 원칙 - Single Responsibility Principle (SRP; 단일 책임 원칙) (0) | 2023.05.16 |
---|---|
Android Studio 깨끗하게 정리하기 (0) | 2023.01.29 |
[FastAPI + React] 소셜 로그인 구현하기 - 구글 로그인 (0) | 2022.09.18 |
[FastAPI + React] 소셜 로그인 구현하기 - 이메일 로그인 (2) | 2022.09.16 |
[FastAPI + React] 소셜 로그인 구현하기 - 기본 환경 구축 (0) | 2022.09.13 |