add loggers for kakao login
parent
219d8798ad
commit
7038faaf74
|
|
@ -4,6 +4,7 @@
|
|||
카카오 로그인, 토큰 갱신, 로그아웃, 내 정보 조회 엔드포인트를 제공합니다.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Header, Request, status
|
||||
|
|
@ -12,6 +13,8 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||
|
||||
from config import prj_settings
|
||||
from app.database.session import get_session
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from app.user.dependencies import get_current_user
|
||||
from app.user.models import User
|
||||
from app.user.schemas.user_schema import (
|
||||
|
|
@ -40,7 +43,9 @@ async def kakao_login() -> KakaoLoginResponse:
|
|||
프론트엔드에서 이 URL로 사용자를 리다이렉트하면
|
||||
카카오 로그인 페이지가 표시됩니다.
|
||||
"""
|
||||
logger.info("[ROUTER] 카카오 로그인 URL 요청")
|
||||
auth_url = kakao_client.get_authorization_url()
|
||||
logger.debug(f"[ROUTER] 카카오 인증 URL 생성 완료 - auth_url: {auth_url}")
|
||||
return KakaoLoginResponse(auth_url=auth_url)
|
||||
|
||||
|
||||
|
|
@ -63,6 +68,8 @@ async def kakao_callback(
|
|||
|
||||
신규 사용자인 경우 자동으로 회원가입이 처리됩니다.
|
||||
"""
|
||||
logger.info(f"[ROUTER] 카카오 콜백 수신 - code: {code[:20]}...")
|
||||
|
||||
# 클라이언트 IP 추출
|
||||
ip_address = request.client.host if request.client else None
|
||||
|
||||
|
|
@ -71,6 +78,8 @@ async def kakao_callback(
|
|||
if forwarded_for:
|
||||
ip_address = forwarded_for.split(",")[0].strip()
|
||||
|
||||
logger.debug(f"[ROUTER] 클라이언트 정보 - ip: {ip_address}, user_agent: {user_agent}")
|
||||
|
||||
result = await auth_service.kakao_login(
|
||||
code=code,
|
||||
session=session,
|
||||
|
|
@ -84,6 +93,7 @@ async def kakao_callback(
|
|||
f"?access_token={result.access_token}"
|
||||
f"&refresh_token={result.refresh_token}"
|
||||
)
|
||||
logger.info(f"[ROUTER] 카카오 콜백 완료, 프론트엔드로 리다이렉트 - redirect_url: {redirect_url[:50]}...")
|
||||
return RedirectResponse(url=redirect_url, status_code=302)
|
||||
|
||||
|
||||
|
|
@ -119,6 +129,8 @@ async def kakao_verify(
|
|||
|
||||
신규 사용자인 경우 자동으로 회원가입이 처리됩니다.
|
||||
"""
|
||||
logger.info(f"[ROUTER] 카카오 인가 코드 검증 요청 - code: {body.code[:20]}...")
|
||||
|
||||
# 클라이언트 IP 추출
|
||||
ip_address = request.client.host if request.client else None
|
||||
|
||||
|
|
@ -127,13 +139,18 @@ async def kakao_verify(
|
|||
if forwarded_for:
|
||||
ip_address = forwarded_for.split(",")[0].strip()
|
||||
|
||||
return await auth_service.kakao_login(
|
||||
logger.debug(f"[ROUTER] 클라이언트 정보 - ip: {ip_address}, user_agent: {user_agent}")
|
||||
|
||||
result = await auth_service.kakao_login(
|
||||
code=body.code,
|
||||
session=session,
|
||||
user_agent=user_agent,
|
||||
ip_address=ip_address,
|
||||
)
|
||||
|
||||
logger.info(f"[ROUTER] 카카오 인가 코드 검증 완료 - user_id: {result.user.id}, is_new_user: {result.user.is_new_user}")
|
||||
return result
|
||||
|
||||
|
||||
@router.post(
|
||||
"/refresh",
|
||||
|
|
|
|||
|
|
@ -71,24 +71,36 @@ class AuthService:
|
|||
Returns:
|
||||
LoginResponse: 토큰 및 사용자 정보
|
||||
"""
|
||||
logger.info(f"[AUTH] 카카오 로그인 시작 - code: {code[:20]}..., ip: {ip_address}")
|
||||
|
||||
# 1. 카카오 토큰 획득
|
||||
logger.info("[AUTH] 1단계: 카카오 토큰 획득 시작")
|
||||
kakao_token = await kakao_client.get_access_token(code)
|
||||
logger.debug(f"[AUTH] 카카오 토큰 획득 완료 - token_type: {kakao_token.token_type}")
|
||||
|
||||
# 2. 카카오 사용자 정보 조회
|
||||
logger.info("[AUTH] 2단계: 카카오 사용자 정보 조회 시작")
|
||||
kakao_user_info = await kakao_client.get_user_info(kakao_token.access_token)
|
||||
logger.debug(f"[AUTH] 카카오 사용자 정보 조회 완료 - kakao_id: {kakao_user_info.id}")
|
||||
|
||||
# 3. 사용자 조회 또는 생성
|
||||
logger.info("[AUTH] 3단계: 사용자 조회/생성 시작")
|
||||
user, is_new_user = await self._get_or_create_user(kakao_user_info, session)
|
||||
logger.info(f"[AUTH] 사용자 처리 완료 - user_id: {user.id}, is_new_user: {is_new_user}")
|
||||
|
||||
# 4. 비활성화 계정 체크
|
||||
if not user.is_active:
|
||||
logger.error(f"[AUTH] 비활성화 계정 접근 시도 - user_id: {user.id}")
|
||||
raise UserInactiveError()
|
||||
|
||||
# 5. JWT 토큰 생성
|
||||
logger.info("[AUTH] 5단계: JWT 토큰 생성 시작")
|
||||
access_token = create_access_token(user.id)
|
||||
refresh_token = create_refresh_token(user.id)
|
||||
logger.debug(f"[AUTH] JWT 토큰 생성 완료 - user_id: {user.id}")
|
||||
|
||||
# 6. 리프레시 토큰 DB 저장
|
||||
logger.info("[AUTH] 6단계: 리프레시 토큰 저장 시작")
|
||||
await self._save_refresh_token(
|
||||
user_id=user.id,
|
||||
token=refresh_token,
|
||||
|
|
@ -96,11 +108,16 @@ class AuthService:
|
|||
user_agent=user_agent,
|
||||
ip_address=ip_address,
|
||||
)
|
||||
logger.debug(f"[AUTH] 리프레시 토큰 저장 완료 - user_id: {user.id}")
|
||||
|
||||
# 7. 마지막 로그인 시간 업데이트
|
||||
user.last_login_at = datetime.now(timezone.utc)
|
||||
await session.commit()
|
||||
|
||||
redirect_url = f"https://{prj_settings.PROJECT_DOMAIN}"
|
||||
logger.info(f"[AUTH] 카카오 로그인 완료 - user_id: {user.id}, redirect_url: {redirect_url}")
|
||||
logger.debug(f"[AUTH] 응답 토큰 정보 - access_token: {access_token[:30]}..., refresh_token: {refresh_token[:30]}...")
|
||||
|
||||
return LoginResponse(
|
||||
access_token=access_token,
|
||||
refresh_token=refresh_token,
|
||||
|
|
@ -113,7 +130,7 @@ class AuthService:
|
|||
profile_image_url=user.profile_image_url,
|
||||
is_new_user=is_new_user,
|
||||
),
|
||||
redirect_url=f"{prj_settings.PROJECT_DOMAIN}",
|
||||
redirect_url=redirect_url,
|
||||
)
|
||||
|
||||
async def refresh_tokens(
|
||||
|
|
|
|||
|
|
@ -4,10 +4,14 @@
|
|||
카카오 로그인 인증 흐름을 처리하는 클라이언트입니다.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
import aiohttp
|
||||
|
||||
from config import kakao_settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from app.user.exceptions import KakaoAPIError, KakaoAuthFailedError
|
||||
from app.user.schemas.user_schema import KakaoTokenResponse, KakaoUserInfo
|
||||
|
||||
|
|
@ -39,12 +43,15 @@ class KakaoOAuthClient:
|
|||
Returns:
|
||||
카카오 OAuth 인증 페이지 URL
|
||||
"""
|
||||
return (
|
||||
auth_url = (
|
||||
f"{self.AUTH_URL}"
|
||||
f"?client_id={self.client_id}"
|
||||
f"&redirect_uri={self.redirect_uri}"
|
||||
f"&response_type=code"
|
||||
)
|
||||
logger.info(f"[KAKAO] 인증 URL 생성 - redirect_uri: {self.redirect_uri}")
|
||||
logger.debug(f"[KAKAO] 인증 URL 상세 - auth_url: {auth_url}")
|
||||
return auth_url
|
||||
|
||||
async def get_access_token(self, code: str) -> KakaoTokenResponse:
|
||||
"""
|
||||
|
|
@ -60,6 +67,7 @@ class KakaoOAuthClient:
|
|||
KakaoAuthFailedError: 토큰 발급 실패 시
|
||||
KakaoAPIError: API 호출 오류 시
|
||||
"""
|
||||
logger.info(f"[KAKAO] 액세스 토큰 요청 시작 - code: {code[:20]}...")
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
data = {
|
||||
|
|
@ -72,20 +80,27 @@ class KakaoOAuthClient:
|
|||
if self.client_secret:
|
||||
data["client_secret"] = self.client_secret
|
||||
|
||||
logger.debug(f"[KAKAO] 토큰 요청 데이터 - redirect_uri: {self.redirect_uri}, client_id: {self.client_id[:10]}...")
|
||||
|
||||
async with session.post(self.TOKEN_URL, data=data) as response:
|
||||
result = await response.json()
|
||||
logger.debug(f"[KAKAO] 토큰 응답 상태 - status: {response.status}")
|
||||
|
||||
if "error" in result:
|
||||
error_desc = result.get(
|
||||
"error_description", result.get("error", "알 수 없는 오류")
|
||||
)
|
||||
logger.error(f"[KAKAO] 토큰 발급 실패 - error: {result.get('error')}, description: {error_desc}")
|
||||
raise KakaoAuthFailedError(f"카카오 토큰 발급 실패: {error_desc}")
|
||||
|
||||
logger.info("[KAKAO] 액세스 토큰 발급 성공")
|
||||
logger.debug(f"[KAKAO] 토큰 정보 - token_type: {result.get('token_type')}, expires_in: {result.get('expires_in')}")
|
||||
return KakaoTokenResponse(**result)
|
||||
|
||||
except KakaoAuthFailedError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"[KAKAO] API 호출 오류 - error: {str(e)}")
|
||||
raise KakaoAPIError(f"카카오 API 호출 중 오류 발생: {str(e)}")
|
||||
|
||||
async def get_user_info(self, access_token: str) -> KakaoUserInfo:
|
||||
|
|
@ -102,21 +117,31 @@ class KakaoOAuthClient:
|
|||
KakaoAuthFailedError: 사용자 정보 조회 실패 시
|
||||
KakaoAPIError: API 호출 오류 시
|
||||
"""
|
||||
logger.info("[KAKAO] 사용자 정보 조회 시작")
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
|
||||
async with session.get(self.USER_INFO_URL, headers=headers) as response:
|
||||
result = await response.json()
|
||||
logger.debug(f"[KAKAO] 사용자 정보 응답 상태 - status: {response.status}")
|
||||
|
||||
if "id" not in result:
|
||||
logger.error(f"[KAKAO] 사용자 정보 조회 실패 - response: {result}")
|
||||
raise KakaoAuthFailedError("카카오 사용자 정보를 가져올 수 없습니다.")
|
||||
|
||||
kakao_id = result.get("id")
|
||||
kakao_account = result.get("kakao_account", {})
|
||||
profile = kakao_account.get("profile", {})
|
||||
|
||||
logger.info(f"[KAKAO] 사용자 정보 조회 성공 - kakao_id: {kakao_id}")
|
||||
logger.debug(f"[KAKAO] 사용자 상세 정보 - nickname: {profile.get('nickname')}, email: {kakao_account.get('email')}")
|
||||
return KakaoUserInfo(**result)
|
||||
|
||||
except KakaoAuthFailedError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"[KAKAO] API 호출 오류 - error: {str(e)}")
|
||||
raise KakaoAPIError(f"카카오 API 호출 중 오류 발생: {str(e)}")
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue