📌 Django에서 네이버 OAuth2 로그인 구현하기
✅ 1. 네이버 애플리케이션 등록
NAVER Developers 사이트에서 애플리케이션을 등록합니다.
- 콜백 URL: /oauth/naver/callback/
- 발급받은 클라이언트 ID 및 시크릿은 secret.json 파일에 보관
- 네이버 로그인 -> 연락처 이메일주소 -> 서비스 URL : http://localhost:8000
- callback : http://localhost:8000/oauth/naver/callback/
- client ID 등록
{
"DJANGO_SECRET_KEY": "django-insecure-@cggy0b%9ie&7g_15nnh+4la@0xx3q!%vxuda24bs0x1a%b0y$",
"email": {
"user":"jangpanjangsu@naver.com",
"password":"secret_Id"
},
"naver": {
"client_id":"client_id",
"secret": "secret_Id"
}
}
# settings.py
NAVER_CLIENT_ID = SECRET['naver']['client_id']
NAVER_SECRET = SECRET['naver']['secret']
참고 문서: 네이버 로그인 API 명세서
reqeusts 설치
poetry add requests
member 에 oauth.py 에 구축
## member/oauth_views.py
from urllib.parse import urlencode
import requests
from django.conf import settings
from django.contrib.auth import get_user_model, login
from django.core import signing
from django.http import Http404
from django.shortcuts import redirect, render
from django.urls import reverse
from django.views.generic import RedirectView
from member.forms import NicknameForm
User = get_user_model()
NAVER_CALLBACK_URL = '/oauth/naver/callback/'
NAVER_STATE = 'naver_login'
NAVER_LOGIN_URL = 'https://nid.naver.com/oauth2.0/authorize'
NAVER_TOKEN_URL = 'https://nid.naver.com/oauth2.0/token'
NAVER_PROFILE_URL = 'https://openapi.naver.com/v1/nid/me'
class NaverLoginRedirectView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
domain = self.request.scheme + '://' + self.request.META.get('HTTP_HOST', '')
callback_url = domain + NAVER_CALLBACK_URL
state = signing.dumps(NAVER_STATE)
params = {
'response_type': 'code',
'client_id': settings.NAVER_CLIENT_ID,
'redirect_uri': callback_url,
'state': state
}
return f'{NAVER_LOGIN_URL}?{urlencode(params)}'
def naver_callback(request):
code = request.GET.get('code')
state = request.GET.get('state')
if NAVER_STATE != signing.loads(state):
raise Http404
access_token = get_naver_access_token(code, state)
profile_response = get_naver_profile(access_token)
print('profile request', profile_response)
email = profile_response.get('email')
user = User.objects.filter(email=email).first()
if user:
if not user.is_active:
user.is_active = True
user.save()
login(request, user)
return redirect('main')
return redirect(
reverse('oauth:nickname') + f'?access_token={access_token}'
)
def oauth_nickname(request):
access_token = request.GET.get('access_token')
if not access_token:
return redirect('login')
form = NicknameForm(request.POST or None)
if form.is_valid():
user = form.save(commit=False)
profile = get_naver_profile(access_token)
email = profile.get('email')
if User.objects.filter(email=email).exists():
raise Http404
user.email = email
user.is_active = True
user.set_password(User.objects.make_random_password())
user.save()
login(request, user)
return redirect('main')
return render(request, 'auth/nickname.html', {'form': form})
def get_naver_access_token(code, state):
params = {
'grant_type': 'authorization_code',
'client_id': settings.NAVER_CLIENT_ID,
'client_secret': settings.NAVER_SECRET,
'code': code,
'state': state
}
response = requests.get(NAVER_TOKEN_URL, params=params)
result = response.json()
return result.get('access_token')
def get_naver_profile(access_token):
headers = {
'Authorization': f'Bearer {access_token}'
}
response = requests.get(NAVER_PROFILE_URL, headers=headers)
if response.status_code != 200:
raise Http404
result = response.json()
return result.get('response')
Naver document -> API명세서에서 -> API 기본 정보 및 네이버 로그인 인증 요청(수동확인방법)
https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=i1YFd5mqZDibnX4tpGWE&redirect_uri=http://localhost:8000/naver/callback/&state=abc
URL 등록
#settings/urls.py
# include
path('oauth/', include('member.oauth_urls')),
#members/oauth_urls.py
from django.urls import path
from . import oauth_views
app_name = 'oauth'
urlpatterns = [
# naver
path('naver/login/', oauth_views.NaverLoginRedirectView.as_view(), name='naver_login'),
path('naver/callback/', oauth_views.naver_callback, name='naver_callback'),
path('nickname/', oauth_views.oauth_nickname, name='nickname'),
]
login.html 에 추가
<!-- templates/auth/login.html -->
{% extends 'base.html' %}
{% block content %}
<h1 class="title">로그인</h1>
<form method="POST">
{% csrf_token %}
{% include 'include/form.html' %}
<button class="btn btn-primary">로그인</button>
</form>
<a href="{% url 'oauth:naver_login' %}" class="btn btn-success mt-3">
네이버 로그인
</a>
{% endblock %}
models/forms.py 닉네임등록
class NicknameForm(BootstrapModelForm):
class Meta:
model = User
fields = ('nickname', )
labels = {
'nickname': '닉네임을 입력하여 회원가입을 마무리해주세요.'
}
include/form.html 세로정렬되게 폼수정
{% for field in form %}
<div class="form-group mb-3">
<label class="form-label" for="{{ field.auto_id }}">{{ field.label }}</label>
{{ field }}
{% for error in field.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
member/ model.py 에서 random 패스워드 설정 (장고 BaseUserManager 에서 random비번 기능 삭제)
class UserManager(BaseUserManager):
def create_user(self, email, password):
if not email:
raise ValueError('올바른 이메일을 입력하세요.')
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.is_active = False
user.save(using=self._db)
return user
def create_superuser(self, email, password):
user = self.create_user(email, password)
user.is_admin = True
user.is_active = True
user.save(using=self._db)
return user
def make_random_password(self, length=10):
import random, string
chars = string.ascii_letters + string.digits
return ''.join(random.choices(chars, k=length))
🔐 2. 네이버 로그인 핵심 흐름 요약
- 사용자가 로그인 버튼 클릭
- 네이버 로그인 페이지로 리디렉션
- 로그인 후 콜백 URL로 인증 코드 반환
- 인증 코드로 Access Token 요청
- Access Token으로 사용자 정보 요청
- 기존 유저인지 확인 후 로그인 또는 회원가입 진행
🧩 주요 뷰 및 함수 설명
✅ NaverLoginRedirectView
class NaverLoginRedirectView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
...
- 역할: 네이버 인증 페이지로 리디렉션
- 핵심: 인증 요청 파라미터 (response_type, client_id, redirect_uri, state) 구성 후 로그인 URL 반환
✅ naver_callback(request)
def naver_callback(request):
...
- 역할: 네이버 인증 후 콜백 처리
- 작업 흐름:
- 네이버로부터 인증 코드 및 상태(state) 수신
- Access Token 요청 → get_naver_access_token()
- 사용자 정보 조회 → get_naver_profile()
- 기존 유저면 로그인, 없으면 닉네임 입력 페이지로 리디렉션
✅ oauth_nickname(request)
def oauth_nickname(request):
...
- 역할: 회원가입 시 닉네임을 입력받는 뷰
- 동작:
- form 유효성 검사 → 유저 생성
- 프로필 정보 기반 이메일 저장, 비밀번호는 랜덤 생성
- 로그인 후 메인 페이지로 이동
✅ get_naver_access_token(code, state)
def get_naver_access_token(code, state):
...
- 역할: Access Token 요청
- 요청 파라미터: client_id, client_secret, code, state
- 응답: JSON 형태의 access_token 반환
✅ get_naver_profile(access_token)
def get_naver_profile(access_token):
...
- 역할: 사용자 정보 조회 API 호출
- 헤더: Authorization: Bearer <access_token>
- 응답 내용: 사용자 email, name 등 반환
🔁 전체 흐름 요약
[클라이언트] → 네이버 로그인 페이지 → 인증 완료 후 콜백
→ Access Token 요청 → 프로필 조회
→ 유저 존재 여부 확인 → 로그인 or 회원가입
💡 확장 아이디어
기능 설명
자동 회원가입 | 닉네임 없이도 이메일 기반으로 가입 처리 |
프로필 이미지 저장 | 네이버 프로필 사진도 가져와 저장 가능 |
카카오 / 구글 연동 | 동일한 구조로 손쉽게 확장 가능 |
네이버 OAuth2 로그인을 통해 사용자는 별도 회원가입 없이도 빠르고 안전하게 로그인할 수 있으며, 다양한 인증 수단과 쉽게 통합할 수 있습니다 🔐
'Django' 카테고리의 다른 글
Chapter 12-1 Django TDD(Test-Driven Development)란? (0) | 2025.05.19 |
---|---|
Chapter 11-5 Django Mini Project - GitHub OAuth2 로그인 구현 (0) | 2025.05.16 |
Chapter 11-3 Django OAuth2 완전 정복 - 인증과 권한 부여의 표준 프레임워크 (0) | 2025.05.16 |
Chapter 11-2 Django 인스타그램 프로젝트 - 검색 기능 구현 정리 (0) | 2025.05.16 |
Chapter 11-1 Django 인스타그램 프로젝트 - 팔로워 / 팔로잉 목록 모달 구현하기 (0) | 2025.05.16 |