인증은 플러그인 형태로 구성되어야 합니다.
— 제이콥 카플란-모스(Jacob Kaplan-Moss), "REST worst practices" 중에서
인증은 들어오는 요청을 식별하는 자격 증명(예: 요청을 보낸 사용자 또는 요청에 서명된 토큰)을 연결하는 메커니즘입니다. 그런 다음 권한 및 제한 정책은 해당 자격 증명을 사용하여 요청을 허용할지 여부를 결정할 수 있습니다.
REST 프레임워크는 기본적으로 여러 인증 방식을 제공하며, 사용자 정의 인증 방식을 구현할 수도 있습니다.
인증은 권한 및 제한 검사 전에 항상 뷰의 가장 처음에 실행되며, 다른 코드가 진행되기 전에 수행됩니다.
request.user 속성은 일반적으로 contrib.auth 패키지의 User 클래스의 인스턴스로 설정됩니다.
request.auth 속성은 추가적인 인증 정보를 위해 사용됩니다. 예를 들어, 요청에 서명된 인증 토큰을 나타내는 데 사용할 수 있습니다.
참고: 인증 자체만으로는 들어오는 요청을 허용하거나 거부하지 않으며, 단지 요청에 사용된 자격 증명을 식별하는 역할만 합니다.
API에 대한 권한 정책을 설정하는 방법에 대해서는 권한(permissions) 문서를 참조하세요.
인증 방식은 항상 클래스들의 목록으로 정의됩니다. REST 프레임워크는 해당 목록에 있는 각 클래스와 인증을 시도하고, 첫 번째로 인증에 성공한 클래스의 반환 값을 사용하여 request.user와 request.auth를 설정합니다.
어떤 클래스도 인증에 성공하지 못하면, request.user는 django.contrib.auth.models.AnonymousUser의 인스턴스로 설정되고, request.auth는 None으로 설정됩니다.
인증되지 않은 요청에 대한 request.user와 request.auth의 값을 UNAUTHENTICATED_USER 및 UNAUTHENTICATED_TOKEN 설정을 통해 수정할 수 있습니다.
기본 인증 방식은 DEFAULT_AUTHENTICATION_CLASSES 설정을 사용하여 전역적으로 설정할 수 있습니다. 예를 들면 다음과 같습니다.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}
또한, APIView 기반의 뷰나 뷰셋(ViewSet)별로 인증 방식을 설정할 수도 있습니다.
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'user': str(request.user), # `django.contrib.auth.User` 인스턴스
'auth': str(request.auth), # None
}
return Response(content)
혹은 함수형 뷰에서 @api_view 데코레이터를 사용할 때:
@api_view(['GET'])
@authentication_classes([SessionAuthentication, BasicAuthentication])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
content = {
'user': str(request.user), # `django.contrib.auth.User` 인스턴스
'auth': str(request.auth), # None
}
return Response(content)
인증되지 않은 요청이 권한이 거부되었을 때, 두 가지 서로 다른 오류 코드가 사용될 수 있습니다.
HTTP 401 응답에는 항상 클라이언트에게 인증 방법을 알려주는 WWW-Authenticate 헤더가 포함되어야 합니다. 반면, HTTP 403 응답에는 WWW-Authenticate 헤더가 포함되지 않습니다.
사용할 응답의 종류는 인증 방식에 따라 결정됩니다. 여러 인증 방식이 사용될 수 있지만, 응답 유형을 결정하는 데에는 오직 하나의 방식만 사용됩니다. 응답 유형을 결정할 때는 뷰에서 첫 번째로 설정된 인증 클래스가 사용됩니다.
또한, 요청이 인증에 성공했지만 여전히 권한이 거부될 수 있으며, 이 경우 인증 방식과 관계없이 항상 HTTP 403 Permission Denied 응답이 사용됩니다.
Apache에서 mod_wsgi를 사용하여 배포할 때, 기본적으로 인증 헤더가 WSGI 애플리케이션으로 전달되지 않습니다. 이는 Apache에서 인증이 처리될 것으로 가정되기 때문입니다. 따라서, 세션 기반이 아닌 인증 방식을 사용할 경우, 필요한 헤더를 애플리케이션으로 전달하도록 mod_wsgi를 명시적으로 설정해야 합니다. 이를 위해 WSGIPassAuthorization 지시어를 적절한 컨텍스트에 추가하고 'On'으로 설정할 수 있습니다.
# 이 설정은 서버 설정, 가상 호스트, 디렉터리 또는 .htaccess에 추가할 수 있습니다.
WSGIPassAuthorization On
이 인증 방식은 사용자의 사용자명과 비밀번호로 서명된 HTTP Basic Authentication을 사용합니다. 기본 인증은 일반적으로 테스트 목적으로만 적합합니다.
인증이 성공하면 BasicAuthentication은 다음과 같은 자격 증명을 제공합니다.
request.user는 Django User 인스턴스가 됩니다.request.auth는 None이 됩니다.권한이 거부된 인증되지 않은 응답은 적절한 WWW-Authenticate 헤더와 함께 HTTP 401 Unauthorized 응답을 반환합니다. 예를 들어:
WWW-Authenticate: Basic realm="api"
주의: BasicAuthentication을 프로덕션 환경에서 사용할 경우 API가 HTTPS를 통해서만 제공되도록 해야 하며, API 클라이언트가 로그인 시 사용자명과 비밀번호를 항상 재요청하고, 이 세부 정보를 영구 저장소에 저장하지 않도록 해야 합니다.
주의: Django REST Framework에서 제공하는 토큰 인증은 비교적 간단한 구현입니다. 한 사용자당 여러 개의 토큰을 지원하고, 보안 구현이 강화된 기능을 원한다면, Django REST Knox 패키지를 참고하십시오.
이 인증 방식은 간단한 토큰 기반의 HTTP 인증 방식을 사용하며, 토큰 인증은 네이티브 데스크톱 및 모바일 클라이언트와 같은 클라이언트-서버 환경에 적합합니다.
TokenAuthentication 방식을 사용하려면 인증 클래스를 TokenAuthentication로 구성하고, INSTALLED_APPS 설정에 rest_framework.authtoken을 추가해야 합니다.
INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
설정을 변경한 후에는 manage.py migrate 명령을 실행하세요. rest_framework.authtoken 앱은 Django 데이터베이스 마이그레이션을 제공합니다.
사용자에 대한 토큰도 생성해야 합니다.
from rest_framework.authtoken.models import Token
token = Token.objects.create(user=...)
print(token.key)
클라이언트가 인증하려면, 토큰 키를 Authorization HTTP 헤더에 포함시켜야 합니다. 키 앞에는 "Token"이라는 문자열 리터럴을 추가하고 두 문자열 사이에는 공백을 넣습니다. 예를 들어:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
다른 키워드를 사용하고 싶다면, TokenAuthentication을 서브클래스화하고 keyword 클래스 변수를 설정할 수 있습니다.
인증에 성공하면 TokenAuthentication은 다음 자격 증명을 제공합니다.
request.user는 Django User 인스턴스가 됩니다.request.auth는 rest_framework.authtoken.models.Token 인스턴스가 됩니다.권한이 거부된 인증되지 않은 응답은 적절한 WWW-Authenticate 헤더와 함께 HTTP 401 Unauthorized 응답을 반환합니다. 예를 들어:
WWW-Authenticate: Token
토큰 인증된 API를 테스트할 때는 curl 명령줄 도구가 유용할 수 있습니다. 예를 들어:
curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'
주의: 프로덕션 환경에서 TokenAuthentication을 사용할 경우, API가 HTTPS를 통해서만 제공되도록 해야 합니다.
모든 사용자에게 자동으로 생성된 토큰을 부여하려면, 사용자의 post_save 신호를 캐치할 수 있습니다.
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
이 코드 스니펫을 설치된 models.py 모듈에 추가하거나, Django가 시작 시 임포트하는 위치에 배치하세요.
이미 사용자가 생성된 경우, 기존 사용자에게 토큰을 생성하려면 다음과 같이 할 수 있습니다.
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
for user in User.objects.all():
Token.objects.get_or_create(user=user)
TokenAuthentication을 사용하는 경우, 클라이언트가 사용자명과 비밀번호를 제공하여 토큰을 얻을 수 있는 메커니즘을 제공해야 할 수 있습니다. 이를 위해 REST Framework는 이 동작을 제공하는 기본 뷰를 제공합니다. URLconf에 obtain_auth_token 뷰를 추가하세요.
from rest_framework.authtoken import views
urlpatterns += [
path('api-token-auth/', views.obtain_auth_token)
]
이 뷰는 유효한 사용자명과 비밀번호 필드를 POST 요청으로 보내면 JSON 응답을 반환합니다.
{ 'token': '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
기본적으로 obtain_auth_token 뷰는 설정에 있는 기본 렌더러 및 파서 클래스를 사용하는 대신 JSON 요청 및 응답을 명시적으로 사용합니다.
기본적으로 obtain_auth_token 뷰에는 권한 또는 트래픽 제한이 적용되지 않습니다. 트래픽 제한을 적용하려면 뷰 클래스를 오버라이드하고 throttle_classes 속성을 사용하여 포함해야 합니다.
obtain_auth_token 뷰의 커스텀 버전이 필요하면 ObtainAuthToken 뷰 클래스를 서브클래싱하고 이를 URL 설정에 사용하면 됩니다.
예를 들어, 토큰 값 외에 추가 사용자 정보를 반환할 수 있습니다:
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
class CustomAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'token': token.key,
'user_id': user.pk,
'email': user.email
})
urls.py에서는 다음과 같이 사용됩니다:
urlpatterns += [
path('api-token-auth/', CustomAuthToken.as_view())
]
토큰을 관리자 인터페이스를 통해 수동으로 생성할 수도 있습니다. 대규모 사용자 기반을 사용하는 경우, TokenAdmin 클래스를 수정하여 사용자 필드를 raw_field로 선언하는 것을 권장합니다.
your_app/admin.py에서:
from rest_framework.authtoken.admin import TokenAdmin
TokenAdmin.raw_id_fields = ['user']
manage.py 명령어 사용버전 3.6.4부터는 다음 명령어를 사용하여 사용자 토큰을 생성할 수 있습니다:
./manage.py drf_create_token <username>
이 명령어는 주어진 사용자에 대한 API 토큰을 반환하며, 토큰이 없을 경우 생성합니다:
Generated token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b for user user1
토큰이 유출되었거나 손상된 경우, 추가 매개변수를 전달하여 토큰을 재생성할 수 있습니다:
./manage.py drf_create_token -r <username>
이 인증 방식은 Django의 기본 세션 백엔드를 사용하여 인증을 처리합니다. Session 인증은 웹사이트와 동일한 세션 컨텍스트에서 실행되는 AJAX 클라이언트에 적합합니다.
성공적으로 인증되면 SessionAuthentication은 다음 자격 증명을 제공합니다:
request.user는 Django의 User 인스턴스가 됩니다.request.auth는 None이 됩니다.인증되지 않은 요청이 거부된 경우, HTTP 403 Forbidden 응답을 반환합니다.
AJAX 스타일의 API와 함께 SessionAuthentication을 사용하는 경우, PUT, PATCH, POST 또는 DELETE 요청과 같은 "안전하지 않은" HTTP 메서드 호출에 대해 유효한 CSRF 토큰을 포함해야 합니다. 자세한 내용은 Django CSRF 문서를 참조하세요.
주의사항 로그인 페이지를 만들 때는 항상 Django의 표준 로그인 뷰를 사용하세요. 이렇게 하면 로그인 뷰가 적절하게 보호됩니다.
REST 프레임워크에서 CSRF 검증은 세션 기반과 비세션 기반 인증을 모두 지원해야 하기 때문에 기본 Django와 약간 다르게 동작합니다. 이는 인증된 요청만 CSRF 토큰이 필요하며, 익명 요청은 CSRF 토큰 없이 전송될 수 있음을 의미합니다. 이 동작은 로그인 뷰에 적합하지 않으며, 로그인 뷰에는 항상 CSRF 검증이 적용되어야 합니다.
이 인증 방식은 웹 서버가 REMOTE_USER 환경 변수를 설정하도록 위임하여 인증을 처리합니다.
사용하려면 django.contrib.auth.backends.RemoteUserBackend (또는 하위 클래스)를 AUTHENTICATION_BACKENDS 설정에 포함해야 합니다. 기본적으로 RemoteUserBackend는 이미 존재하지 않는 사용자 이름에 대해 User 객체를 생성합니다. 이 동작 및 기타 동작을 변경하려면 Django 문서를 참조하세요.
성공적으로 인증되면 RemoteUserAuthentication은 다음 자격 증명을 제공합니다:
request.user는 Django의 User 인스턴스가 됩니다.request.auth는 None이 됩니다.웹 서버의 인증 방법을 설정하는 방법에 대한 정보는 해당 서버의 문서를 참조하세요:
사용자 정의 인증 스킴을 구현하려면 BaseAuthentication을 서브클래싱하고 .authenticate(self, request) 메서드를 오버라이드해야 합니다. 이 메서드는 인증이 성공하면 (user, auth) 튜플을 반환하거나, 인증이 실패하면 None을 반환해야 합니다.
일부 상황에서는 None을 반환하는 대신 .authenticate() 메서드에서 AuthenticationFailed 예외를 발생시킬 수 있습니다.
일반적으로 다음 접근 방식을 취해야 합니다:
None을 반환합니다. 사용 중인 다른 인증 스킴도 여전히 확인됩니다.AuthenticationFailed 예외를 발생시킵니다. 권한 검사를 확인하지 않고 즉시 오류 응답이 반환됩니다.또한 .authenticate_header(self, request) 메서드를 오버라이드할 수 있습니다. 이 메서드가 구현된 경우, HTTP 401 Unauthorized 응답에서 WWW-Authenticate 헤더 값으로 사용할 문자열을 반환해야 합니다.
.authenticate_header() 메서드를 오버라이드하지 않으면, 인증되지 않은 요청이 접근이 거부될 때 HTTP 403 Forbidden 응답이 반환됩니다.
참고 요청 객체의 .user 또는 .auth 속성에 의해 사용자 정의 인증기가 호출될 때, AttributeError가 WrappedAttributeError로 다시 발생할 수 있습니다. 이는 원래 예외가 외부 속성 접근에 의해 억제되는 것을 방지하기 위한 것입니다. 파이썬은 AttributeError가 사용자 정의 인증기에서 발생한 것으로 인식하지 않고 대신 요청 객체에 .user 또는 .auth 속성이 없다고 가정할 것입니다. 이러한 오류는 validator에 의해 수정되거나 처리되어야 합니다.
다음 예는 X-USERNAME이라는 사용자 정의 요청 헤더에 있는 사용자 이름으로 모든 들어오는 요청을 인증합니다:
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
username = request.META.get('HTTP_X_USERNAME')
if not username:
return None
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
raise exceptions.AuthenticationFailed('No such user')
return (user, None)
다음과 같은 외부 패키지들도 사용할 수 있습니다.
django-rest-knox
django-rest-knox 라이브러리는 내장된 TokenAuthentication 스킴보다 더 안전하고 확장 가능한 방식으로 토큰 기반 인증을 처리할 수 있는 모델과 뷰를 제공합니다. 이 패키지는 싱글 페이지 애플리케이션과 모바일 클라이언트를 염두에 두고 설계되었으며, 클라이언트 별로 토큰을 제공하고, 일부 다른 인증(일반적으로 기본 인증)을 제공하면 토큰을 생성하는 뷰, 서버에서 강제 로그아웃을 처리하는 토큰 삭제 뷰, 사용자가 로그인한 모든 클라이언트를 로그아웃시키는 뷰 등을 제공합니다.
Django OAuth Toolkit
Django OAuth Toolkit 패키지는 OAuth 2.0 지원을 제공하며 Python 3.4 이상에서 작동합니다. 이 패키지는 jazzband에서 유지 관리되며 뛰어난 OAuthLib을 사용합니다. 이 패키지는 문서화가 잘 되어 있고 지원이 잘 이루어지고 있어 현재 OAuth 2.0 지원을 위한 권장 패키지입니다.
설치 및 설정
pip을 사용하여 설치합니다.
pip install django-oauth-toolkit
패키지를 INSTALLED_APPS에 추가하고, REST 프레임워크 설정을 수정합니다.
INSTALLED_APPS = [
...
'oauth2_provider',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
]
}
자세한 내용은 Django REST framework - Getting started 문서를 참조하십시오.
Django REST framework OAuth
Django REST framework OAuth 패키지는 REST 프레임워크에 대해 OAuth1 및 OAuth2 지원을 제공합니다.
이 패키지는 이전에 REST 프레임워크에 직접 포함되었으나 현재는 외부 패키지로 지원 및 유지 관리되고 있습니다.
설치 및 설정
pip을 사용하여 패키지를 설치합니다.
pip install djangorestframework-oauth
설정 및 사용 방법에 대한 자세한 내용은 Django REST framework OAuth 문서를 참조하십시오.
JSON Web Token Authentication
JSON Web Token(JWT)은 비교적 새로운 표준으로 토큰 기반 인증에 사용할 수 있습니다. 내장된 TokenAuthentication 스킴과 달리, JWT 인증은 토큰을 검증하기 위해 데이터베이스를 사용할 필요가 없습니다. JWT 인증을 위한 패키지로는 djangorestframework-simplejwt가 있으며, 이 패키지는 일부 기능과 함께 플러그 가능한 토큰 블랙리스트 앱을 제공합니다.
Hawk HTTP Authentication
HawkREST 라이브러리는 Mohawk 라이브러리를 기반으로 하여 API에서 Hawk로 서명된 요청과 응답을 처리할 수 있도록 합니다. Hawk는 공유된 키로 서명된 메시지를 사용하여 두 당사자가 안전하게 통신할 수 있도록 해줍니다. 이는 HTTP MAC 액세스 인증을 기반으로 하며, 이는 OAuth 1.0의 일부를 기반으로 합니다.
HTTP Signature Authentication
HTTP Signature(현재 IETF 초안)는 HTTP 메시지에 대한 출처 인증 및 메시지 무결성을 달성하는 방법을 제공합니다. Amazon의 HTTP Signature 스킴과 유사하게, 이 방식은 상태 비저장 방식의 요청별 인증을 허용합니다. Elvio Toccalino는 djangorestframework-httpsignature(현재 구버전) 패키지를 유지 관리하고 있으며, 이 패키지는 HTTP Signature 인증 메커니즘을 쉽게 사용할 수 있도록 제공합니다. 업데이트된 djangorestframework-httpsignature fork 버전은 drf-httpsig입니다.
Djoser
Djoser 라이브러리는 회원가입, 로그인, 로그아웃, 비밀번호 재설정, 계정 활성화와 같은 기본 작업을 처리하는 뷰 세트를 제공합니다. 이 패키지는 사용자 정의 모델을 사용하며, 토큰 기반 인증을 사용합니다. 이는 Django 인증 시스템의 REST 구현으로 사용할 수 있습니다.
django-rest-auth / dj-rest-auth
이 라이브러리는 회원가입, 인증(소셜 인증 포함), 비밀번호 재설정, 사용자 정보 조회 및 업데이트 등의 기능을 제공하는 REST API 엔드포인트를 제공합니다. 이러한 API 엔드포인트를 통해 AngularJS, iOS, Android 등의 클라이언트 앱이 Django 백엔드 사이트와 독립적으로 REST API를 통해 사용자 관리를 할 수 있습니다.
현재 이 프로젝트에는 두 개의 fork가 있습니다.
django-rest-auth는 원래의 프로젝트지만 현재 업데이트가 이루어지지 않고 있습니다.dj-rest-auth는 이 프로젝트의 새로운 fork입니다.drf-social-oauth2
drf-social-oauth2는 Facebook, Google, Twitter, Orcid 등 주요 소셜 OAuth2 공급자를 사용한 인증을 도와주는 프레임워크입니다. 설정이 간단하며 JWT 방식으로 토큰을 생성합니다.
drfpasswordless
drfpasswordless는 Medium과 Square Cash에서 영감을 받아 Django REST 프레임워크의 TokenAuthentication 스킴에 패스워드 없는 지원을 추가합니다. 사용자는 이메일 주소나 휴대폰 번호와 같은 연락처로 전송된 토큰을 사용하여 로그인하거나 가입합니다.
django-rest-authemail
django-rest-authemail은 사용자 가입 및 인증을 위한 RESTful API 인터페이스를 제공합니다. 사용자 이름 대신 이메일 주소를 인증에 사용합니다. API 엔드포인트는 회원가입, 이메일 인증, 로그인, 로그아웃, 비밀번호 재설정, 비밀번호 재설정 확인, 이메일 변경, 이메일 변경 확인, 비밀번호 변경, 사용자 정보 조회를 제공합니다. 완전히 작동하는 예제 프로젝트와 자세한 설명서가 포함되어 있습니다.
Django-Rest-Durin
Django-Rest-Durin은 여러 웹/CLI/모바일 API 클라이언트에 대해 하나의 인터페이스로 토큰 인증을 처리하되, 각 API 클라이언트별로 서로 다른 토큰 구성을 허용하는 라이브러리입니다. 이 패키지는 여러 사용자별 토큰을 지원하며, 토큰 만료 시간은 API 클라이언트마다 다르게 설정할 수 있으며, Django 관리자 인터페이스에서 사용자 정의할 수 있습니다.
더 많은 정보는 문서를 참조하십시오.