(5.3) 장고 토큰 인증- 로그인 구현하기_
영어쌤이 만드는 회원가입, 인증[CRUD] 만들어욤! 리액트와 파이썬 장고

- 이번엔 로그인을 구현하여 작동하고 있는 Authentication에 적용하도록 합니다.
(11) /leadmanager/accounts/serializers.py || Validation(인증) 코드 작성 작업
- 다음과 같이 #Login Serializer 및에 인증 기능을 하는 serializer를 만들어 줍니다.

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
32
33
34
35
36
37
|
// /leadmanager/account/serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
# User Serializer
# 유저(사용자) 시리얼라이저는 간단하기도하고 Delete serializer와도 매우 유사합니다.
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email')
# Register Serializer
class RegisterSerializer(serialigers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'password')
extra_kwards = {'password': {'write_only': True}}
def create(self, validated_data):
usere = User.objects.create_user(validated_data
['username'], validated_data['email'], validated_data['password'])
return user
# Login Serializer
# 여기선 ModelSerializer로 선언하지 않습니다.
# 새롭게 만드는 것이 아닌 validate 즉, 로그인시 인증하는 용도이기 때문입니다.
class LoginSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()
def validate.(self, data):
user = authenticate(**data)
if user and user.is_active:
return user
raise serializers.ValidationError("Incorrect Credentials")
|
cs |
(12) /accounts/api.py 에 Validation(인증) 코드 작성
- 먼저 .serializers 에서 로그인 기능도 가져옵니다.

- api.py 하단엔 Login API 코드를 작성해 줍니다.

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
32
33
34
35
36
37
38
|
// /leadmanager/account/api.py
from rest_framework import generics, permissions
from rest_framework.response import Response
from knox.models import AuthToken
from .serializers import UserSerializer, RegisterSerializser, LoginSerializer
# Register API
class RegisterAPI(generics.GenericAPIView)
serializer_class = RegisterSerializer
## kwargs basically means it can take more arguments
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
# 위의 save 코드로 인해 data가 저장됨
return Response({
"user": UserSerializer(user,
context=self.get_serializer_context()).data,
"token": AuthToken.objects.create(user)[1]
})
# Login API
class LoginAPI(generics.GenericAPIView):
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data
# 위의 validated_data로써 계정 인증을
return Response({
"user": UserSerializer(user,
context=self.get_serializer_context()).data,
"token": AuthToken.objects.create(user)[1]
})
# Get User API
|
cs |
(13) /accounts/urls.py 에 validation(인증) endpoint 작성하기
- 다음과 같이 Validation(인증) 또는 Login 에 관한 코드를 추가 착성해 주세요.

1
2
3
4
5
6
7
8
9
10
|
// /leadmanager/accounts/urls.py 작성
from django.ruls import path, include
from .api import RegisterAPI, LoginAPI
from knox import views as knox_views
urlpatterns = [
path('api.auth', include('knox.urls')),
path('api/auth/register', RegisterAPI.as_view()),
path('api/auth/login', LoginAPI.as_view()),
]
|
cs |
(14) Postman으로 로그인(인증)테스트 진행
- 다음과 같이 포스트맨에서 POST 기능을 사용합니다.
- 입력할 url은 http://[ip 주소]:[지정한 포트 번호]/api/auth/login 입니다.
- Headers 탭에서 KEY는 Content-Type, VALUE는 application/json 으로 지정해 줍니다.

- Body 에선 조건을 raw로 선택합니다.
- 그리고 다음과 같이 앞서 Authentication 과정 중 권한 토큰을 부여해 준 계정 이외의 계정을 입력해 주어 인증(Validating)을 진행합니다.
- json 형식의 data를 입력하면 됩니다.

1
2
3
4
|
{
"username":"brad",
"password":"123456"
}
|
cs |
- Send를 클릭하여 결과를 확인합니다.
- 결과는 다음과 같이 Bad request(400) 그리고 미리 입력해 줬던 예외처리 메세지(Incorrect Credentials) 가 발생하면 성공한 것 입니다.

- 다음으로는 일전에 인증 권한을 부여해준 계정으로 테스트를 합니다.

- 결과는 다음과 같이 인증이 완료되고 해당 로그인 계정에 대한 토큰 또한 확인할 수 있습니다.

- 이렇게 우리는 인증 등록 및 로그인 기능을 가지고 있는 서버를 구성하였습니다.
- 다음은 Get User API를 만들어 Token과 함께 사용자 계정 정보를 얻을 수 있도록 합니다.
(15) /accounts/api.py || Get user 기능을 하는 코드를 작성합니다.
- api.py 문서 하단에 Get User API 추가 작성

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
// /leadmanager/accounts/api.py
from rest_framework import generics, permissions
from rest_framework.response import Response
from knox.models import AuthToken
from .serializers import UserSerializer, RegisterSerializser, LoginSerializer
# Register API
class RegisterAPI(generics.GenericAPIView)
serializer_class = RegisterSerializer
## kwargs basically means it can take more arguments
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
# 위의 save 코드로 인해 data가 저장됨
return Response({
"user": UserSerializer(user,
context=self.get_serializer_context()).data,
"token": AuthToken.objects.create(user)[1]
})
# Login API
class LoginAPI(generics.GenericAPIView):
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data
# 위의 validated_data로써 계정 인증을 함
return Response({
"user": UserSerializer(user,
context=self.get_serializer_context()).data,
"token": AuthToken.objects.create(user)[1]
})
# Get User API
class UserAPI(generics.RetrieveAPIView):
permission_classes = [
permissions.IsAuthenticated,
]
serializer_class = UserSerializer
def get_object(self):
return self.request.user
|
cs |
(16) /accounts/urls.py || get user api 관련 코드 추가 작성
- 다음과 같이 UserAPI 를 가지고 와 적용합니다.

1
2
3
4
5
6
7
8
9
10
11
|
// /leadmanager/accounts/urls.py 작성
from django.ruls import path, include
from .api import RegisterAPI, LoginAPI, UserAPI
from knox import views as knox_views
urlpatterns = [
path('api.auth', include('knox.urls')),
path('api/auth/register', RegisterAPI.as_view()),
path('api/auth/login', LoginAPI.as_view()),
path('api/auth/user', UserAPI.as_view()),
]
|
cs |
(17) Postman 으로 테스트하기
- postman에서 GET 요청 가능을 사용 합니다.
- url은 http://[IP 주소]:[포트번호]/api/auth/user 입니다.
- 1차 테스트는 바로 Send 버튼을 클릭해 GET 요청을 보내는 것으로 시작합니다.

- Credential 정보를 입력하지 않았다고 메세지가 출력됩니다.
- 원하는 결과를 얻기 위해선 다음과 같이 Headers 탭으로 가 Key와 VALUE를 제공해 주면 됩니다.
- KEY는 Authorization 입니다.
- VALUE는 Token [인증시 부여받은 토큰 번호] 를 입력해 주면 됩니다. (이때 Token과 [토큰 번호] 사이에 스페이스 한 칸을 띄어 주세요!)

- 정상적으로 값들을 입력했다면 위와 같이 200번 정상 코드와 함께 인증 정보를 확인할 수 있습니다.
- 만일 입력해준 정보중 단 한개의 문자라도 다르게 입력해 주면, 예를 들면 토큰 번호에 다른 숫자를 하나 더 추가한다던지 하는...(속된 말로 장난질이라고 하죵???) 다음과 같은 에러 메세지를 받게 됩니다.


(18) 사용자 계정들에 인증 토큰을 부여하는 루틴
(18-1) registerAPI를 통해 토큰을 부여해줄 계정 정보를 입력한다.
- url: http://localhost:8000/api/auth/register
- Headers에서 KEY: Content-Type // VALUE: application/json 설정

- Body에서 raw 조건에서 json 형식으로 토큰을 부여할 (기존에 생성하여 리스트에 있는)사용자 정보를 입력 및 Post 요청(Send 버튼 클릭)

(18-2) 부여받은 토큰을 확인한다.

(18-3) GET 요청 // 토큰을 부여받은 계정 정보 확인
- url: http://localhost:8000/api/auth/user
- KEY: Authorization, VALUE: Token [토큰 번호(ctrl+v)]
- GET 요청(Send 버튼 클릭)

(19) Logout API 구현하기
- 로그인(인증) 기능을 구현했으니 이젠 로그아웃 기능도 부여해 계정 정보를 보호해 줘야 합니다.
(20) /accounts/urls.py || Logout API 추가 작성
- 가끔 사용자들이 프론트엔드 단에서 로그아웃했다고 다 끝난 것으로 보는 경우도 있는데, 실제 로그아웃이 된 것은 아닙니다. 토큰이 계속해서 살아있기 때문입니다.
- 그렇기 때문에 보안을 위해서라도 Logout api를 추가하여 부여받은 토큰을 없애주도록 해야 합니다.
- urls.py에는 다음과 같이 추가 작성을 해 줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
|
// /leadmanager/accounts/urls.py 작성
from django.ruls import path, include
from .api import RegisterAPI, LoginAPI, UserAPI
from knox import views as knox_views
urlpatterns = [
path('api.auth', include('knox.urls')),
path('api/auth/register', RegisterAPI.as_view()),
path('api/auth/login', LoginAPI.as_view()),
path('api/auth/user', UserAPI.as_view()),
path('api/auth/logout', knox_views.LogoutView.as_view(), name='knox_logout')
]
|
cs |

(21) Postman으로 Logout 테스트하기(토큰 죽이기)
- POST 요청으로 logout api 를 실행합니다.
- url: http://localhost:8000/api/auth/logout
- KEY: Authorization, VALUE: Token [토큰 번호]
- Logout POST를 요청하면 다음과 같은 결과를 얻습니다. (204 No Content)

- 그러고 나면 Body에선 아무런 출력 결과를 받을 수 없는데, 그때 user(url)로 인증 과정을 해당 토큰을 넣은 상태에서 POST 요청(Send 버튼 클릭, 인증 요청)을 하면 다음과 같이 Invalid token 이라는 메세지를 받게 됩니다.

(22) 로그아웃 과정
a. 로그아웃을 하면, 해당 토큰을 죽여서 무효화 시킵니다.
b. 사용자는 다시 로그인을 해 새로운 토큰을 받습니다.
c. 그렇게 새로이 받게 된 토큰을 통해 인증을 받고 권한을 부여받아 안전히 보호가 되는 페이지로 접근하게 됩니다.
이렇게 프론트엔드만 줄창 하던 저도 어렵게 느껴지던 Python Django 를 통해 쉽고 빠르게 이해하고 익히고 사용할 수 있게 되었습니다. 다른 분들도 힘내시길 바랍니다!
어쨌든 이렇게 Python-Django Authentication은 완료가 되었습니다.
다음 순서는
(6) Front-end에서 인증(Authentication)을 조작하는 일을 할 것 입니다.
Login, Registration, React와 Redux를 통해 Endpoint와의 반응형 구현과 같은 것들로 구성해 인증의 전체 구성을 할 것 입니다.
잘자요!! 저는 조금 쉬었다가 바로 시작해야겠네요!