59 lines
2.2 KiB
Python
59 lines
2.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""카카오 OAuth 클라이언트 (castad app/user/services/kakao.py 이식·축약).
|
|
|
|
흐름: get_authorization_url() → 사용자 카카오 로그인 → 인가코드(code)
|
|
→ get_access_token(code) → get_user_info(token) → (id, nickname, email)
|
|
"""
|
|
from fastapi import HTTPException
|
|
|
|
import aiohttp
|
|
|
|
from .config import settings
|
|
|
|
AUTH_URL = "https://kauth.kakao.com/oauth/authorize"
|
|
TOKEN_URL = "https://kauth.kakao.com/oauth/token"
|
|
USER_INFO_URL = "https://kapi.kakao.com/v2/user/me"
|
|
|
|
|
|
def get_authorization_url() -> str:
|
|
if not settings.KAKAO_CLIENT_ID:
|
|
raise HTTPException(501, "카카오 로그인 미설정 — KAKAO_CLIENT_ID 필요")
|
|
return (
|
|
f"{AUTH_URL}?client_id={settings.KAKAO_CLIENT_ID}"
|
|
f"&redirect_uri={settings.KAKAO_REDIRECT_URI}&response_type=code"
|
|
)
|
|
|
|
|
|
async def get_access_token(code: str) -> str:
|
|
data = {
|
|
"grant_type": "authorization_code",
|
|
"client_id": settings.KAKAO_CLIENT_ID,
|
|
"redirect_uri": settings.KAKAO_REDIRECT_URI,
|
|
"code": code,
|
|
}
|
|
if settings.KAKAO_CLIENT_SECRET:
|
|
data["client_secret"] = settings.KAKAO_CLIENT_SECRET
|
|
async with aiohttp.ClientSession() as s:
|
|
async with s.post(TOKEN_URL, data=data) as r:
|
|
res = await r.json()
|
|
if "error" in res:
|
|
raise HTTPException(400, f"카카오 토큰 발급 실패: {res.get('error_description', res.get('error'))}")
|
|
return res["access_token"]
|
|
|
|
|
|
async def get_user_info(access_token: str) -> dict:
|
|
"""카카오 사용자 → {kakao_id:int, nickname:str|None, email:str|None, profile_image:str|None}."""
|
|
async with aiohttp.ClientSession() as s:
|
|
async with s.get(USER_INFO_URL, headers={"Authorization": f"Bearer {access_token}"}) as r:
|
|
if r.status != 200:
|
|
raise HTTPException(500, "카카오 사용자 정보 조회 실패")
|
|
info = await r.json()
|
|
acc = info.get("kakao_account") or {}
|
|
prof = acc.get("profile") or {}
|
|
return {
|
|
"kakao_id": int(info["id"]),
|
|
"nickname": prof.get("nickname"),
|
|
"email": acc.get("email"),
|
|
"profile_image": prof.get("profile_image_url"),
|
|
}
|