TOP
본문 바로가기
[파이썬 Projects]/<파이썬 웹개발>

[파이썬] FastAPI - 메모 앱 프로젝트 9: 소셜 로그인 추가(네이버)

by 기록자_Recordian 2025. 5. 12.
728x90
반응형
이전 내용
 

[파이썬] FastAPI - 메모 앱 프로젝트 9: 소셜 로그인 추가(카카오)

이전 내용 [파이썬] FastAPI - 메모 앱 프로젝트 9: 소셜 로그인 추가(구글)이전 내용 [파이썬] FastAPI - 메모 앱 프로젝트 8: MVC 패턴이전 내용 [파이썬] FastAPI - 메모 앱 프로젝트 7: 보완(회원가입 등)

puppy-foot-it.tistory.com


FastAPI에서 OAuth2 구현
3. 네이버

 

이번엔 소셜 로그인의 마지막, 네이버 로그인 기능을 구현해 본다.

네이버의 경우, 네이버 디벨로퍼(하단 링크)에서 진행할 수 있고, 

https://developers.naver.com/docs/login/devguide/devguide.md

애플리케이션을 만들어서 ClientID, Secret을 발급받고 Redirect URI를 등록하는 작업은 프레임워크와 무관하게 동일하므로 하단의 글을 확인한다.

 

[Java] Spring Boot: 네이버 로그인 구현하기

이전 내용 [Java] Spring Boot: 카카오 로그인 기능 추가하기이전 내용 [Java] Spring Boot: 구글 로그인 기능 추가하기이전 내용 전반적인 순서1. Gradle 또는 Maven 의존성 추가2. 구글 API Console 설정 - 구글 개

puppy-foot-it.tistory.com

 

Callback URL에는 아래의 두 가지(http://, https://)를 추가하도록 한다.

http://localhost:8000/naver/login/callback

https://localhost:8000/naver/login/callback

 

그리고나서, .env 파일에 네이버 로그인 정보를 등록한다.

◆ .env

NAVER_CLIENT_ID=YOUR_CLIENT_ID
NAVER_CLIENT_SECRET=YOUR_CLIENT_SECRET_KEY
NAVER_REDIRECT_URI=http://localhost:8000/naver/login/callback

 

◆  oauth/naver.py

oauth 디렉터리 내에 naver.py 파일을 생성하여 아래와 같이 코드를 작성한다. (google.py 내용 활용하여 일부 수정)

import os
import httpx
from fastapi import APIRouter, Request, Depends
from dotenv import load_dotenv
from fastapi.templating import Jinja2Templates
from dependencies import get_db
from sqlalchemy.orm import Session
from controllers import create_or_update_social_user
from fastapi.responses import RedirectResponse

load_dotenv()
router = APIRouter()
templates = Jinja2Templates(directory="templates")

NAVER_AUTH_URL = "https://nid.naver.com/oauth2.0/authorize"
NAVER_TOKEN_URL = "https://nid.naver.com/oauth2.0/token"
NAVER_USERINFO_URL = "https://openapi.naver.com/v1/nid/me"

CLIENT_ID = os.getenv("NAVER_CLIENT_ID")
CLIENT_SECRET = os.getenv("NAVER_CLIENT_SECRET")
REDIRECT_URI = os.getenv("NAVER_REDIRECT_URI")

@router.get("/auth/naver/login")
def login():
    auth_url = (
        f"{NAVER_AUTH_URL}?response_type=code"
        f"&client_id={CLIENT_ID}"
        f"&redirect_uri={REDIRECT_URI}"
        f"&scope=openid%20email%20profile"
    )
    return RedirectResponse(url=auth_url)

@router.get("/naver/login/callback")
async def callback(request: Request, db: Session = Depends(get_db)):  # get_db() 사용
    code = request.query_params.get("code")
    
    async with httpx.AsyncClient() as client:
        token_res = await client.post(NAVER_TOKEN_URL, data={
            'code': code,
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'
        })
        
        if token_res.status_code != 200:
            return {"error": "Failed to retrieve token"}

        access_token = token_res.json().get("access_token")

        # 사용자 정보 요청
        userinfo_res = await client.get(NAVER_USERINFO_URL, headers={
            'Authorization': f'Bearer {access_token}'
        })

        if userinfo_res.status_code != 200:
            return {"error": "Failed to retrieve user information"}

        # 사용자 정보 처리
        user_info_raw = userinfo_res.json()
        naver_response = user_info_raw.get("response", {})
        user_info = {
            "username": naver_response.get("name") or "User",  # 이름 없으면 기본값
            "email" : naver_response.get("email"),
            "naver_id" : naver_response.get("id")
        }

        user = create_or_update_social_user(db, user_info, provider='naver')

        return templates.TemplateResponse("memos.html", {"request": request, "user_info": user})

 

※ 소셜 로그인 제공자마다 사용자 정보(JSON)의 구조가 다르다.

제공자 구조 접근 방식
구글 평탄(flat) user_info["email"], user_info["id"]
카카오 부분 중첩 user_info["kakao_account"]["profile"]["nickname"]
네이버 전체 중첩 user_info["response"]["email"], ["name"], ["id"]

 

네이버의 경우, 실제 데이터는 response라는 키 안에 들어가 있어

{
  "resultcode": "00",
  "message": "success",
  "response": {
    "id": "naver-user-id",
    "email": "abc@naver.com",
    "name": "홍길동"
  }
}

 

naver_response 라는 변수를 추가해 response에서 id, email, name 등의 정보를 추출하도록 변경한다.

user_info_raw = userinfo_res.json()
naver_response = user_info_raw.get("response", {})  # 중첩된 response에서 추출

user_info = {
    "username": naver_response.get("name") or "User",
    "email": naver_response.get("email"),
    "naver_id": naver_response.get("id")
}

 

그리고 main.py 파일에서 이전에 주석처리 했던 naver 라우터와 oauth 디렉터리의 naver를 추가하는 부분을 주석 해제한다.

◆ main.py

from oauth import naver

app.include_router(naver.router) # NAVER OAuth2 라우터 포함

 

models.py 파일에는 이전에 카카오를 구현할 때 User 모델에 naver_id 칼럼을 미리 추가해 뒀으므로 생략

◆ models.py

# 사용자 모델 정의
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True, index=True)  # 정수형, PK
    username = Column(String(100), unique=True, index=True, nullable=True)  # 소셜 로그인 시 자동 설정 가능
    email = Column(String(200), unique=True)  # 이메일은 유일해야 함
    hashed_password = Column(String(512), nullable=True)  # 비밀번호는 선택적
    google_id = Column(String(100), unique=True, index=True, nullable=True)  # 구글 계정의 고유 ID
    kakao_id = Column(String(100), unique=True, index=True, nullable=True) # 카카오 계정의 고유 ID
    naver_id = Column(String(100), unique=True, index=True, nullable=True) # 네이버 계정의 고유 ID

 

역시 home.html 에도 NAVER 로그인 버튼을 미리 만들어뒀으므로 생략

    <div class="buttons">
        <button onclick="window.location.href='/auth/google/login'">Google 계정으로 로그인</button>
    </div>
    <div class="buttons">
        <button onclick="window.location.href='/auth/kakao/login'">KAKAO 계정으로 로그인</button>
    </div>
    <div class="buttons" style="margin-bottom: 2rem;">
        <button onclick="window.location.href='/auth/naver/login'">NAVER 계정으로 로그인</button>
    </div>
</form>

 

★ 개발자센터에 등록되지 않은 사이트에서 로그인을 시도했습니다. 서비스 설정에 오류가 있어 확인이 필요합니다. 에러 해결

main.py를 실행하여 서버를 실행하고 네이버 로그인을 했는데, 아래와 같은 에러 메시지가 발생하는 경우,

 

네이버 디벨로퍼의 애플리케이션의 리다이렉트 URI에 localhost 말고 숫자로 된 URL(127.0.0.1)도 등록해준다.

(코드를 수정할 필요는 없다, 예).env)

 

http://127.0.0.1:8000/naver/login/callback

https://127.0.0.1:8000/naver/login/callback

해당 Callback URL을 추가한 뒤, 네이버 로그인 버튼을 클릭해보면

네이버 로그인도 잘 실현된 것을 확인할 수 있다.


[참고]

https://remazitensi.tistory.com/entry/FastAPI%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%A1%9C%EA%B7%B8%EC%9D%B8-API%EC%99%80-%EC%97%B0%EB%8F%99

 


다음 내용

 

[파이썬] FastAPI - 메모 앱 프로젝트 10: 환영 이메일 발송

이전 내용 [파이썬] FastAPI - 메모 앱 프로젝트 9: 소셜 로그인 추가(네이버)이전 내용 [파이썬] FastAPI - 메모 앱 프로젝트 9: 소셜 로그인 추가(카카오)이전 내용 [파이썬] FastAPI - 메모 앱 프로젝트 9:

puppy-foot-it.tistory.com

728x90
반응형