TIL 06-10 Vue와 DRF 결합하기 2 - Authentication & Permission

김덕협·2026년 6월 10일

TIL

목록 보기
23/43

[DRF] 인증(Authentication)과 권한(Permission) 정리

Vue with DRF 학습 중 백엔드(DRF)에서의 인증권한 처리 과정을 정리
프론트엔드(Vue)와 백엔드(DRF)는 인증 구현 시 각각 다음과 같이 역할을 나눠 맡음.

  • DRF(백엔드): 사용자 정보를 검증하고, 안전한 토큰을 발급하며, 어떤 요청이 허가되는지 권한 규칙을 정한다.
  • Vue(프론트엔드): 로그인 폼을 제공하고, 발급받은 토큰을 저장하며, 보호된 요청을 보낼 때 토큰을 함께 전송한다.

이 글에서는 백엔드에서의 인증·권한 과정을 집중적으로 다룬다.


1. 인증 with DRF

사전 준비

인증 로직 진행을 위해 User 모델 관련 코드를 활성화한다.

(1) Article 모델에 user ForeignKey 연결

# articles/models.py

class Article(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE
    )
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

(2) Serializer에 read_only_fields 설정

# articles/serializers.py

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'
        read_only_fields = ('user',)

💡 read_only_fields : 사용자가 직접 수정하면 안 되는 필드. (user는 서버가 채워준다)

(3) View에서 게시글 생성 시 user 정보 저장

# articles/views.py

@api_view(['GET', 'POST'])
# @permission_classes([IsAuthenticated])
def article_list(request):
    ...
    elif request.method == 'POST':
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            # serializer.save()
            serializer.save(user=request.user)   # 요청을 보낸 user를 함께 저장
            return Response(serializer.data, status=status.HTTP_201_CREATED)

(4) DB 초기화 및 재마이그레이션

  1. DB 초기화
    • db.sqlite3 삭제
    • migrations 파일 삭제
  2. Migration 과정 재진행
  3. fixturesarticles.jsonuser 정보가 없으므로 loaddata 불가능

인증의 필요성 [복습]

  • 클라이언트와 서버 간의 상태 정보를 유지하기 위해서 쿠키와 세션을 사용한다.
  • 하지만 클라이언트와 서버는 사용자를 식별하지 못하고 있는 상태다.
  • 그래서 사용자를 식별하기 위해 필요한 과정이 바로 인증(Authentication).
  • 다양한 인증 방식이 존재한다.
    • 아이디와 비밀번호
    • 소셜 로그인(OAuth)
    • 생체 인증
  • Django는 사용자 인증과 관련된 가장 중요하고 기본적인 뼈대를 제공한다. → Django Authentication System

DRF에서의 인증

  • 인증은 항상 view 함수 시작 시, 다른 코드의 진행이 허용되기 전에 실행된다.
    • 수신 요청을 해당 요청의 사용자 또는 해당 요청이 서명된 토큰(token)과 같은 자격 증명 자료와 연결한다.
  • 이후 인증이 완료된 자격 증명을 사용하여 권한 및 제한 정책을 확인하고, 요청을 허용해야 하는지를 결정한다.

⚠️ TIP: 인증 자체로는 들어오는 요청을 허용하거나 거부할 수 없으며, 단순히 요청에 사용된 자격 증명만 식별한다는 점에 유의.
(즉, "너 누구야?"까지만 담당하고, "들여보낼지 말지"는 권한이 담당한다.)


승인되지 않은 응답 및 금지된 응답

인증되지 않은 요청이 권한을 거부하는 경우 두 가지 오류 코드로 응답한다.

상태 코드의미설명
401 Unauthorized인증 자격 증명 없음요청에 유효한 인증 자격 증명(Authentication Credentials)이 없어 사용자를 식별할 수 없음 (누구인지 증명할 자료가 없음)
403 Forbidden (Permission Denied)권한 거부서버에 요청이 전달되었지만, 권한 때문에 거절됨. 401과 달리 서버는 클라이언트가 누구인지 알고 있음

📌 추가 메모: 403은 CSRF 토큰이 없을 때도 발생한다.


2. 인증 정책 설정

인증 정책은 두 가지 방법으로 설정할 수 있다.

  1. 전역 설정 : 무조건 우리 서비스를 쓰려면 로그인 필수
  2. View 함수 별 설정

수업에서 배운 것은 function based views 기준이다.

(1) 전역 설정

  • 프로젝트 전체에 적용되는 기본 인증 방식을 정의한다. (settings.py)
  • DEFAULT_AUTHENTICATION_CLASSES를 사용한다.
  • 기본 값 : SessionAuthenticationBasicAuthentication
# settings.py

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

(2) View 함수 별 설정

  • authentication_classes 데코레이터를 사용한다.
  • 개별 view에 지정하여 재정의한다.
from rest_framework.decorators import authentication_classes
from rest_framework.authentication import TokenAuthentication, BasicAuthentication

@api_view(['GET', 'POST'])
@authentication_classes([TokenAuthentication, BasicAuthentication])
def article_list(request):
    pass

💡 데코레이터: 기존 함수를 감싸 특별한 기능을 추가하는 함수.


3. DRF가 제공하는 인증 체계

인증 방식설명
BasicAuthentication요청마다 사용자 이름과 비밀번호를 Base64로 인코딩하여 Authorization 헤더에 담아 보내는 방식
✅ TokenAuthentication로그인 시 발급받은 고유한 토큰(Token)을 Authorization 헤더에 담아 요청함으로써 사용자를 인증하는 방식
SessionAuthenticationDjango의 기본 세션 시스템을 활용하여, 브라우저가 보내는 sessionid 쿠키를 통해 사용자를 인증하는 방식
RemoteUserAuthentication웹 서버 등 외부 시스템이 이미 처리한 인증 결과를 신뢰하고, 전달받은 사용자 이름으로 사용자를 인증하는 방식

📌 TokenAuthentication은 Base64 인코딩 방식을 토큰으로 대체하여 보안성을 높인 방식이다.

Token vs Session 차이

구분TokenSession
담기는 위치헤더(Header)쿠키(Cookie)
전송 주체우리(클라이언트)가 직접 전송브라우저가 전송

TokenAuthentication

  • token 기반 HTTP 인증 체계
  • 로그인 시 발급받은 고유한 토큰을 Authorization 헤더에 담아 요청함으로써 사용자를 인증하는 방식
  • 기본 데스크톱 및 모바일 클라이언트와 같은 클라이언트-서버 설정에 적합

서버가 인증된 사용자에게 토큰을 발급하고, 사용자는 매 요청마다 발급받은 토큰을 요청과 함께 보내 인증 과정을 거친다.

💡 token: 인증 후 발급되는, 사용자의 신원이나 권한을 증명하는 값.


4. Token 인증 설정

TokenAuthentication 적용 과정은 다음 3단계다.

1. 인증 클래스 설정
2. INSTALLED_APPS 추가
3. Migrate 진행

(1) 인증 클래스 설정

  • TokenAuthentication 활성화 코드 주석 해제
  • 전역 인증 정책을 Token 방식으로 설정한다.
# my_api/settings.py

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

📌 settings.py에 설정하는 것은 전역 인증 정책이다.

(2) INSTALLED_APPS 추가

rest_framework.authtoken 주석 해제

# my_api/settings.py

INSTALLED_APPS = [
    'articles',
    'accounts',
    'rest_framework',
    'rest_framework.authtoken',
    ...,
]

(3) Migrate 진행

$ python manage.py migrate

토큰 인증 방식 과정 정리

1. 사용자 로그인              (브라우저 → Django)
2. 사용자 확인               (Django ↔ DB)
3. Token 발급               (Django)
4. 응답 (+ Token)           (Django → 브라우저)
5. 데이터 요청 (+ Token)     (브라우저 → Django)
6. Token 검증               (Django)
7. 응답 (+ 요청 데이터)      (Django → 브라우저)

5. Dj-Rest-Auth 라이브러리

Dj-Rest-Auth 란?

  • 회원가입, 로그인/로그아웃, 비밀번호 재설정, 소셜 로그인 등 다양한 인증 관련 기능을 API 엔드포인트로 제공하는 라이브러리.
  • dj-rest-authdjango.contrib.auth대체하는 것이 아니라, 그 위에 만들어져 기능을 확장한다.

인증 기능을 RESTful API로 제공한다.

설치 및 적용

(1) 설치

$ pip install dj-rest-auth

(2) 추가 App 주석 해제

# my_api/settings.py

INSTALLED_APPS = [
    'articles',
    'accounts',
    'rest_framework',
    'rest_framework.authtoken',
    'dj_rest_auth',
    ...
]

(3) 추가 URL 주석 해제

# my_api/urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('articles.urls')),
    path('accounts/', include('dj_rest_auth.urls')),
    # path('accounts/signup/', include('dj_rest_auth.registration.urls')),
]

Registration(등록) 기능 추가 설정 (Optional, 선택사항)

이전에 설치한 dj-rest-authAPI 인터페이스를 제공하는 역할이고, 실제 로직 실행을 담당할 라이브러리를 추가로 설치한다.

(1) 패키지 추가 설치

$ pip install 'dj-rest-auth[with-social]'

(2) 추가 App 주석 해제

# my_api/settings.py

INSTALLED_APPS = [
    ...,
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'dj_rest_auth.registration',
    ...
]

SITE_ID = 1

💡 SITE_ID : 사이트의 주소 정보를 찾는 데 사용하며, DB의 Site 테이블에서 설정한 ID 값에 매치되는 주소를 사용한다.
INSTALLED_APPSdjango.contrib.sitesdjango_site 테이블을 자동으로 생성한다.

(3) 관련 설정 코드(Middleware) 주석 해제

# my_api/settings.py

MIDDLEWARE = [
    ...,
    'allauth.account.middleware.AccountMiddleware',
]

(4) 추가 URL 주석 해제 후 Migrate 진행

# my_api/urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('articles.urls')),
    path('accounts/', include('dj_rest_auth.urls')),
    path('accounts/signup/', include('dj_rest_auth.registration.urls')),
]
$ python manage.py migrate

6. Token 발급 및 활용

라이브러리 설치로 추가된 URL 목록 확인

http://127.0.0.1:8000/accounts/ 접속 시 404 페이지에서 추가된 URL 패턴을 확인할 수 있다.

accounts/ password/reset/          [name='rest_password_reset']
accounts/ password/reset/confirm/  [name='rest_password_reset_confirm']
accounts/ login/                   [name='rest_login']
accounts/ logout/                  [name='rest_logout']
accounts/ user/                    [name='rest_user_details']
accounts/ password/change/         [name='rest_password_change']
accounts/ signup/

Token 발급 절차

  1. 회원 가입 진행http://127.0.0.1:8000/accounts/signup/
    (Username, Email, Password1, Password2 입력)
  2. 로그인 진행http://127.0.0.1:8000/accounts/login/
    (Username, Email, Password 입력)
  3. 로그인 성공 후 DRF로부터 발급받은 Token 확인
    • 응답으로 {"key": "발급된 토큰 값"} 형태의 Token을 받는다.

이제 이 Token을 Vue에서 별도로 저장하여 매 요청마다 함께 보내야 한다.

기억할 점

  • 로그인을 할 때마다 이 Token 값은 바뀐다.
  • anonymous user : 로그인하지 않은 사용자
  • Postman 기준으로 Headers의 Authorization에 Token Key 값을 넣어서 보내면 인증이 가능하다.

Token 데이터 확인

  • Django DB의 authtoken_token 테이블에서 발급된 토큰을 확인할 수 있다.
  • 발급받은 Token을 인증이 필요한 요청마다 함께 보내야 한다.

클라이언트가 Token으로 인증 받는 방법

게시글 작성 과정을 통해 Token 사용 방법을 익힌다. (Postman 활용)

  1. Authorization HTTP Header에 포함시킨다.
  2. 키 앞에는 문자열 Token이 와야 하며, 공백으로 두 문자열을 구분해야 한다.
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

⚠️ Token과 토큰 값 사이의 공백은 필수다.
Postman → Headers → Key: Authorization, Value: Token 토큰값


7. 권한 with DRF

권한 정책 설정

권한 정책도 인증과 마찬가지로 두 가지 방법으로 설정한다.

  1. 전역 설정
  2. View 함수 별 설정

(1) 전역 설정

  • 프로젝트 전체에 적용되는 기본 권한 방식을 정의한다.
  • DEFAULT_PERMISSION_CLASSES를 사용한다.
  • 기본 값 : rest_framework.permissions.AllowAny
# settings.py

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}

(2) View 함수 별 설정

  • permission_classes 데코레이터를 사용한다.
  • 개별 view에 지정하여 재정의한다.
from rest_framework.decorators import permission_classes
from rest_framework.permissions import IsAuthenticated

@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def article_list(request):
    pass

💡 권한(permissions) : 요청에 대한 접근 허용 또는 거부 여부를 결정한다.


8. DRF가 제공하는 권한 정책

권한 클래스설명
IsAuthenticated인증된(로그인한) 사용자만 접근을 허용
IsAdminUser스태프 권한(is_staff=True)을 가진 관리자 사용자만 접근을 허용
IsAuthenticatedOrReadOnly인증된 사용자는 모든 요청(읽기/쓰기)을 허용하고, 비인증 사용자는 읽기 전용 요청만 허용
AllowAny아무런 제한 없이 모든 사용자의 접근을 허용

(1) IsAuthenticated

  • 개념
    • 인증된 사용자만 접근을 허용하는 권한 클래스
    • 인증되지 않은 사용자의 모든 요청을 거부
  • 특징
    • request.user가 존재하고 인증된 상태인지 확인 → 즉, request.useranonymous user가 아닌지 확인
    • 보호해야 할 중요한 데이터나 리소스에 적합 (예: 회원 전용 페이지, 결제, 프로필 수정 등)

(2) IsAdminUser

  • 개념
    • 관리자(is_staff=True) 권한을 가진 사용자만 접근을 허용하는 권한 클래스
    • 일반 사용자와 비인증 사용자의 모든 요청을 거부
  • 특징
    • request.user.is_staff 속성 값이 True인지 확인하여 권한을 검사
    • 회원 목록 조회, 데이터 통계 등 사이트 관리자에게만 노출되어야 하는 민감한 API에 적합

(3) IsAuthenticatedOrReadOnly

  • 개념
    • 비인증 사용자는 읽기만 허용하고, 인증된 사용자는 모든 요청(읽기/쓰기)을 허용하는 권한 클래스
  • 특징
    • 요청 메서드가 GET, HEAD, OPTIONS와 같은 안전한 메서드일 경우 무조건 허용하고, 그 외 메서드(POST, PUT 등)는 사용자의 인증 여부를 확인
    • 게시글 목록처럼 누구나 볼 수 있지만, 글 작성이나 수정은 회원만 가능한 API에 주로 적용

(4) AllowAny

  • 개념
    • 모든 요청을 무조건 허용하는 권한 클래스
    • 인증된 사용자든, 인증되지 않은 사용자든 상관없이 모두에게 접근을 허용
  • 특징
    • 권한 검사(Authorization) 로직을 전혀 수행하지 않음
    • API 엔드포인트를 완전히 공개하고 싶을 때 사용
    • 보안이 필요한 리소스에는 부적합하므로, 회원가입·로그인 또는 공개 게시글 조회 등 공개 API에 주로 적용

9. IsAuthenticated 설정 & 권한 활용

IsAuthenticated 권한 설정

  • DEFAULT_PERMISSION_CLASSES 주석 해제
  • 기본적으로 모든 View 함수에 대한 접근을 허용 (AllowAny)
# my_api/settings.py

REST_FRAMEWORK = {
    # Authentication
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    # Permission
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ],
}

권한 활용하기 (테스트 시나리오)

상황: 만약 관리자만 전체 게시글 조회가 가능한 권한이 설정되었을 때, 인증된 일반 사용자가 조회 요청을 하면 어떻게 되는지 응답을 확인한다.

① 테스트를 위해 임시로 관리자 권한 클래스 IsAdminUser로 변경

# articles/views.py

from rest_framework.permissions import IsAuthenticated, IsAdminUser

@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])   # 테스트 시 IsAdminUser 로 변경
def article_list(request):
    pass

② 전체 게시글 조회 요청 → 응답 확인

  • http://127.0.0.1:8000/api/v1/articles/
  • 403 Forbidden / 401 Unauthorized(Token 비활성화 후) 응답 확인

IsAdminUser 삭제 후 IsAuthenticated 권한으로 복구

# articles/views.py

from rest_framework.permissions import IsAuthenticated

@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def article_list(request):
    pass

④ 결과 확인

  • 정상 작동하던 게시글 전체 조회가 작동하지 않음 → 401 status code 확인
  • 게시글 조회 요청 시 인증에 필요한 수단(token)을 보내지 않고 있으므로 게시글 조회가 불가능해진 것
  • → 이후 token을 포함시켜 게시글을 조회하는 과정을 진행할 예정

🔑 핵심 요약

  • 인증(Authentication) 은 "너 누구야?"를 식별하는 과정, 권한(Permission) 은 "들여보낼지 말지"를 결정하는 과정이다.
  • 인증은 식별만 할 뿐, 허용·거부는 권한이 결정한다.
  • 401은 신원 증명 자료가 없는 경우, 403은 신원은 알지만 권한이 없는 경우(+ CSRF 토큰 누락 시)다.
  • Token은 헤더에 담겨 클라이언트가 직접 전송하고, Session은 쿠키에 담겨 브라우저가 전송한다.
  • Token은 로그인할 때마다 값이 바뀌며, Authorization: Token <값> 형태로 (공백 구분) 매 요청마다 보내야 한다.
  • 인증/권한 정책 모두 전역 설정(settings.py)View별 설정(데코레이터) 두 가지 방식으로 적용할 수 있다.
profile
뭘봐

0개의 댓글