일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 오블완
- nginx
- redis
- 로그 백업
- slack
- NoSQL
- 물리삭제
- ci/cd
- Airflow
- 논리삭제
- logstash
- prometheus
- Django
- unique constraint
- 티스토리챌린지
- Locust
- JWT
- soft delete
- hard delete
- Next.js
- AWS
- DAG
- grafana
- docker
- Hadoop
- aws ec2
- node exporter
- 계정 관리
- elasticsearch
- hive
- Today
- Total
먹수의 개발일지
[DRF] Responsed Unauthorized 401 in AllowAny permission 본문
프로젝트
- Django Rest Framework
- Django-restframework-jwt (최근에는 djangorestframework-simplejwt 를 권장하고 있다.)
문제
DRF로 REST API를 구현하던 당시에, 프론트 쪽에서 로그인이 필요 없는 상품 리스트 조회 API에서 401 에러가 발생하였다는 이야기를 전달 받았다. 해당 API는 인증을 거치지 않도록 구현했는데 위의 문제가 발생하여 원인을 파악하고자 했다.
우선 프론트쪽에서는 발생한 401 에러는 token이 expired된 상태에서 header에 가지고 있는 상태에서 api를 요청한 상황이었다. 인증이 필요 없는 api에서 인증되지 않은 header 값이 있다고 하더라도 무시하고 response를 주는 것이 맞기 때문에 인증 부분 수정이 필요하다고 판단했다.
테스트
우선 API를 여러 방식으로 테스트한 결과 header에 Authorization 없이 요청하면 값을 잘 불러오지만, Authorizaion이 추가되고 값이 JWT로 시작할 경우 (인증되지 않은 가짜 토큰이나 만료된 토큰 등으로) 요청시 401에러가 발생하는 것을 파악했다.
case 1)
Authorization header 없이 요청 : 통과
case 2)
잘못된 jwt 토큰값(혹은 만료된)을 Authorization header로 요청 : 401 에러
Authentication & Permission
위의 API는 아래와 같이 permission class의 AllowAny를 사용하고 있었다.
views.py
setting에는 기본 권한 정책을 전역적으로 설정해준 상태였다.
settings.py
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES':( 'rest_framework.permissions.AllowAny', ), 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', ), ... }
원인 분석
우선 인증 처리 부분에서 간과했던 부분을 다시 확인해보았다.
- DEFAULT_AUTHENTICATION_CLASSES default 전역 설정
- Authentication과 Permission의 처리 순서이다.
- Authentication이 인증 정보(jwt 토큰 등)로 유저를 먼저 식별하며, 그 다음 Permission을 통해 권한에 따른 요청을 허용할지 거부할지 결정한다.
- AllowAny는 인증 여부에 상관없이 뷰 호출을 허용한다.
의문점
현재로서는 permission_classes에 AllowAny를 줬다고 하더라도, 그 전에 Authentication에서 jwt 토큰을 검사하게 되고 authentication에서 인증되지 않은 유저는 뷰 호출을 허용하지 않고 있다. 잘못된 토큰값을 전달하더라도 접근 허용이 되어야 하지 않을까 싶지만, AllowAny는 예상과 다르게 작동하는 것 같다.
django documentation에도 이에 대해 자세한 설명이 나와있지 않았다. DRF 공식 Git issue들을 살펴보니 버그라는 의견, 논리적 오류라는 의견, 문제가 없다는 의견 등이 있다. 하지만 명확한 답을 주는 글을 찾지 못했다.
*아래는 이슈와 관련된 글들이다.
https://github.com/encode/django-rest-framework/issues/8722
https://github.com/encode/django-rest-framework/issues/7736
[https://stackoverflow.com/questions/72026609/django-rest-framework-api-permission-allowany-authentication-failed]
해결 방법
혼란스럽지만 어쨌든 아래와 같이 @authentication_classes([])
를 줌으로써 default값을 변경해주어 jwt를 검사하지 않도록 지정해주었더니 해결되었다.
당장의 문제는 해결했지만, 이 이슈에 대해 내가 놓친 부분이 있는지 더 알아봐야겠다.
'back-end > Django' 카테고리의 다른 글
[Django] Redis 캐싱으로 성능 최적화 (0) | 2024.11.20 |
---|---|
[Locust] Django와 Locust로 API 부하 테스트 (1) | 2024.11.19 |
Django Signals (0) | 2024.11.10 |