django drf를 이용한 api 테스트 + 토큰 인증

이전 포스팅에 이어서 인증절차를 추가하여 보자.

나중에 React와 연동 할 것이므로 Token기반으로 진행해볼 것이다.

로그인된 사용자만 글을 등록할수 있도록 기능을 추가 구현해보자.
인증방법은 ‘rest_framework.authentication.TokenAuthentication’를 사용한다.

Django DRF 설정

프로젝트의 settings.py 설정

......
......

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'test_api',  # 앱 추가
    'rest_framework.authtoken',  # DRF의 Token 인증 추가
]

......
......

# DRF 기본 설정 (Token 인증 활성화)
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',  # 토큰 인증만 사용
    ],
}

앱의 모델 설정

유저 필드를 추가하여 사용자를 이용할수 있도록 설정을 변경합니다.

from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE)  # 작성자 추가

    def __str__(self):
        return self.title

유저생성

python manage.py createsuperuser

모델 적용

모델을 적용하려하면 기존에 user계정정보가 없어서 경고가 나타날것인데 위 이미지를 참고해서 조치하도록 합니다. 유저를 생성하고, 1을 넣으면 프롬프트가 나올수있는데 이때 int(1)을 넣어서 조치합니다.

python manage.py makemigrations

앱 serializers.py 수정

작성자가 자동 등록될수있도록 수정합니다.
author 필드를 사용자가 직접 입력할 수 없도록 ReadOnlyField로 설정함.

from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):
    author = serializers.ReadOnlyField(source='author.username')  # 작성자 필드를 읽기 전용으로 설정

    class Meta:
        model = Post
        fields = '__all__'

앱 views.py 수정

로그인한 사용자만 등록할수 있도록 수정합니다.

from rest_framework import viewsets, permissions
from .models import Post
from .serializers import PostSerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]  # 로그인한 사용자만 등록 가능

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)  # 현재 로그인된 사용자 저장

토큰인증 API 추가

app의 urls.py를 수정합니다.

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from rest_framework.authtoken.views import obtain_auth_token  # Token 로그인 API 추가
from .views import PostViewSet

router = DefaultRouter()
router.register(r'posts', PostViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('token/', obtain_auth_token, name='api_token_auth'),  # 로그인 후 토큰 발급
]

API 테스트

서버 실행

python manage.py runserver 0.0.0.0:8000

이전 비인증 코드 테스트

import requests

# Django REST API 주소 (로컬 서버 기준)
BASE_URL = "http://192.168.0.202:8000/api/posts/"

# 1️⃣ 게시물 하나 등록 (POST 요청)
post_data = {
    "title": "My API Post",
    "content": "This is a test post created using Python requests library."
}

response = requests.post(BASE_URL, json=post_data)

if response.status_code == 201:  # 201 Created
    print("✅ 게시물이 성공적으로 등록되었습니다!")
    post_id = response.json().get("id")  # 생성된 게시물 ID 가져오기
    print("📌 생성된 게시물 ID:", post_id)
else:
    print("❌ 게시물 등록 실패:", response.status_code, response.text)

# 2️⃣ 게시물 조회 (GET 요청)
response = requests.get(BASE_URL)

if response.status_code == 200:  # 200 OK
    posts = response.json()  # JSON 데이터 파싱
    print("\n📜 현재 등록된 게시물 목록:")
    for post in posts:
        print(f"🆔 ID: {post['id']} | 📌 제목: {post['title']} | 📝 내용: {post['content']}")
else:
    print("❌ 게시물 조회 실패:", response.status_code, response.text)

실행결과

인증 기능 추가된 코드 테스트

import requests

login_data = {
    "username": "admin",
    "password": "P@ssW0rd!"
}

# 로그인하여 토큰 발급
response = requests.post("http://192.168.0.202:8000/api/token/", json=login_data)

if response.status_code == 200:
    token = response.json()["token"]
    print("✅ 로그인 성공! 발급된 토큰:", token)
else:
    print("❌ 로그인 실패:", response.text)

###
# 토큰 인증 헤더 추가
headers = {"Authorization": f"Token {token}"}

# 새 글 등록 요청
post_data = {
    "title": "Auth Post Test",
    "content": "This post is created by a logged-in user!"
}

response = requests.post("http://192.168.0.202:8000/api/posts/", json=post_data, headers=headers)

if response.status_code == 201:
    print("✅ 게시물 등록 성공!", response.json())
else:
    print("❌ 게시물 등록 실패:", response.text)

실행결과