Django REST Framework 튜토리얼 — Class 4: 인증과 권한
풀스택서비스컴퓨팅 강의자료 · 국민대학교 소프트웨어학부
DRF의 핵심 패턴 — GenericAPIView + Mixin, perform_create, ReadOnlyField, 커스텀 BasePermission — 을 Snippet 모델 예제로 학습하고, 30개 단위 테스트로 모든 동작을 검증하는 강의용 저장소입니다.
이 저장소를 따라 끝까지 작성하면 다음을 이해하게 됩니다.
| # | 주제 | 핵심 개념 |
|---|---|---|
| 1 | View 계층 책임 분리 | GenericAPIView(데이터 재료) ↔ Mixin(워크플로우) |
| 2 | 소유자 자동 주입 | perform_create(self, serializer): serializer.save(owner=self.request.user) |
| 3 | 소유자 위조 차단 | owner = serializers.ReadOnlyField(source='owner.username') |
| 4 | 객체 단위 권한 | IsOwnerOrReadOnly 커스텀 권한 + SAFE_METHODS 분기 |
| 5 | 테스트 전략 | 단위 격리 (12) + API 통합 (18) = 30개 테스트 |
| 항목 | 버전 |
|---|---|
| Python | 3.8 이상 |
| Django | 4.x |
| djangorestframework | 3.14+ |
| Git | 2.x |
# 1. 클론
git clone https://github.com/SCKIMOSU/snippets_tutorial.git
cd tutorialclass4
# 2. 가상환경
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 3. 의존성 설치
pip install -r requirements.txt # requirements.txt가 없다면:
# pip install django djangorestframework
# 4. DB 초기화
python manage.py migrate
# 5. 관리자 계정 생성
python manage.py createsuperuser
# 6. 개발 서버 실행
python manage.py runserver 8010브라우저에서 http://127.0.0.1:8010/snippets/ 로 접속하면 DRF Browsable API가 표시됩니다.
# 전체 테스트 (30개)
python manage.py test snippets -v 2
# 특정 클래스만
python manage.py test snippets.tests.SnippetCreateTest
# 커버리지 측정
pip install coverage
coverage run --source=snippets manage.py test snippets
coverage report -m예상 결과:
Found 30 test(s).
...
Ran 30 tests in ~1s
OK
tutorialclass4/
├── manage.py
├── requirements.txt
├── README.md
├── tutorialclass4/ # 프로젝트 설정
│ ├── settings.py
│ └── urls.py
└── snippets/ # Snippet 앱
├── models.py # Snippet (title, code, linenos, language, style, owner)
├── serializers.py # SnippetSerializer (owner = ReadOnlyField)
├── permissions.py # IsOwnerOrReadOnly
├── views.py # SnippetList, SnippetDetail
├── urls.py
├── tests.py # 30 unit tests
└── migrations/
# snippets/views.py
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(owner=self.request.user) # ← 한 줄로 소유자 결정# snippets/serializers.py
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Snippet
fields = ['id', 'title', 'code', 'linenos',
'language', 'style', 'owner']# snippets/permissions.py
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True # 읽기는 모두 허용
return obj.owner == request.user # 쓰기는 소유자만| 영역 | 클래스 | 개수 | 검증 |
|---|---|---|---|
| 단위 격리 | SnippetSerializerTest |
3 | ReadOnlyField의 선언·출력·입력 무시 |
| 단위 격리 | IsOwnerOrReadOnlyUnitTest |
9 | has_object_permission() 직접 호출 |
| API 통합 | SnippetListReadTest |
2 | GET /snippets/ — 익명 허용 |
| API 통합 | SnippetCreateTest |
5 | POST + perform_create + 위조 차단 |
| API 통합 | SnippetDetailReadTest |
3 | GET /snippets// |
| API 통합 | SnippetDetailWriteTest |
8 | PATCH/PUT/DELETE 권한 매트릭스 |
디버깅 원칙: 단위 테스트가 통과하는데 통합이 실패하면 로직은 무죄 — 통합 환경 설정(View · URL · Permission 등록)을 의심.
| 메서드 | 경로 | 동작 | 인증 |
|---|---|---|---|
GET |
/snippets/ |
목록 조회 | 불필요 |
POST |
/snippets/ |
생성 | 필수 |
GET |
/snippets/<pk>/ |
단일 조회 | 불필요 |
PUT / PATCH |
/snippets/<pk>/ |
수정 | 소유자만 |
DELETE |
/snippets/<pk>/ |
삭제 | 소유자만 |
이 저장소는 다음 공격 시나리오를 단위 테스트로 막아냅니다.
| 공격 시나리오 | 방어 메커니즘 | 검증 테스트 |
|---|---|---|
| 익명 사용자가 글 작성 시도 | IsAuthenticatedOrReadOnly |
test_anonymous_cannot_create |
owner=other_user로 위조 전송 |
ReadOnlyField + perform_create |
test_client_cannot_forge_owner_via_request_body |
| 비소유자가 타인 글 수정/삭제 | IsOwnerOrReadOnly.has_object_permission |
test_non_owner_cannot_patch, test_non_owner_cannot_delete |
| 소유자가 PATCH로 소유권 양도 시도 | ReadOnlyField (UPDATE에서도 작동) |
test_patch_cannot_change_owner_even_by_owner |
이 저장소와 짝을 이루는 슬라이드 자료입니다.
| 자료 | 분량 | 내용 |
|---|---|---|
DRF_GenericAPIView_Mixin.pptx |
17장 | 개념 · 패턴 · 책임 분리 · 테스트 전략 |
DRF_Test_Walkthrough.pptx |
11장 | 30개 테스트 메서드별 walkthrough |
- 메인 PPT 1~13장 — 개념 학습
- 본 저장소 코드 직접 작성
python manage.py test snippets— 30개 테스트 통과 확인- 메인 PPT 14~17장 — 테스트 전략 정리
- Walkthrough PPT — 디버깅 reference card로 활용
| 증상 | 원인 | 해결 |
|---|---|---|
NoReverseMatch: 'snippet-list' not found |
urls.py에 name= 누락 |
path(..., name='snippet-list') 추가 |
POST 시 owner 필드 NULL 오류 |
perform_create 누락 |
View.perform_create() 오버라이드 |
| 비소유자가 수정 가능 | permission_classes 누락 |
[IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly] 등록 |
입력에 owner='bob'가 통과됨 |
ReadOnlyField 미선언 |
Serializer에 owner = serializers.ReadOnlyField(...) 추가 |
본 자료는 강의·학습 목적으로 작성되었습니다. 학습 외 용도로 사용 시 출처를 표기해 주시기 바랍니다.
- 강의: 풀스택서비스컴퓨팅
- 소속: 국민대학교 소프트웨어융합대학 소프트웨어학부
- 담당: 김상철 교수 (Prof. Sang-Chul Kim)