Django DRF에서 Token 인증 적용하기

cloud_park·2023년 9월 30일
0

DRF를 배우자

목록 보기
5/6

DRF에서 지원하는 인증

  • SessionAuthentication :
    rest_framework.authentication.SesstionAuthentication
    웹과 장고가 같은 호스트를 쓴다면 사용 가능. 하지만 외부 서비스/앱에서는 사용불가
  • BasicAuthetication :
    rest_framework.authentication.BasicAuthentication
    외부 서비스/앱에서 매번 username/password를 넘기는건 무서운 일
  • TokenAuthentication :
    초기에 username/password로 Token을 발급받고, 이 Token을 API요청에 담아서 인증처리

Token을 생성받는 방법

1. ObatainAuthToekn 뷰를 통한 획득 및 생성 -> URL Mapping필요

rest_framework/authtoken/views.py에 있음. 
class ObtainAuthToekn(APIView):
	def post(self, request, *args, **kwargs): 
	....
    
from rest_framework.authtoken.views import obtain_auth_token

urlpatterns += [
	path(r'api-token-auth/', obtain_auth_token),
]
settings.py

INSTALLED_APPS=[
	...
    'rest_framework',    # Third Apps
    'rest_framework.authtoken',
]

REST_FRAMEWORK = {
	
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ],
    }

이후 Migration을 통해 기본 User모델에 Token 필드를 만들어야한다.

2. Signal을 통한 자동생성

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwards):
	if created:
    	Token.objects.create(user=instance)

3. Management 명령을 통한 생성

python3 manage.py drf_create_token <username>

python3 manage.py drf_create_token -r <username>

Token과 loginRequiredMixin은 같이 사용이 불가능하다!?

Token은 rest_framework에서 지원하고, loginRequriedMixin은 Django에서 지원하는 것이라 서로가 호환이 안되어, Token을 제공했음에도 불구하고 로그인화면을 리턴해버림.
역시 스택오버플로우에는 같은 질문이 있었고, 그걸 해결해준 사람이 있었다.

간단하지만 명료하다. Token이 있으면 loginRequiredMixin을 무시하고, 해당 Token에 대한 인증을 ViewSet에서 수행한다. DRF와 Django의 구현이 다르고, Template과 RESTfulAPI 모두를 사용하게되면 계속 겪게될 문제이니 잘 참고하자.

views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from rest_framework.authentication import SessionAuthentication, TokenAuthentication

class TokenLoginRequiredMixin(LoginRequiredMixin):
    def dispatch(self, request, *args, **kwargs):
        """If token was provided, ignore authenticated status."""
        http_auth = request.META.get("HTTP_AUTHORIZATION")
        if http_auth and "Token" in http_auth:
            pass
        elif not request.user.is_authenticated:
            return self.handle_no_permission()
        return super(LoginRequiredMixin, self).dispatch(
            request, *args, **kwargs)

class MybookWishListViewSet(TokenLoginRequiredMixin, viewsets.ViewSet):
    login_url = f'{settings.FORCE_SCRIPT_NAME}/accounts/login'
    authentication_classes = [
        SessionAuthentication,
        TokenAuthentication,
        ]
profile
Now in progress of untitled advance

0개의 댓글