[TIL - Django] Westagram - 로그인 엔드포인트

haejun-kim·2020년 8월 4일
0

[Django]

목록 보기
14/20
post-thumbnail

회원가입을 마치고 로그인 엔드포인트를 구현해봤다. 로그인 엔드포인트에서 필요하다고 생각한 로직은 다음과 같다.

  • 이메일이나 패스워드는 필수값으로 필요하며, 둘 중 하나라도 빈값으로 들어왔을 경우 에러
  • 로그인 시도했을 때 이메일 데이터를 가지고 오고, 해당 이메일에 맞는 비밀번호를 입력해야만 정상 동작
  • 해당 이메일에 맞지 않는 비밀번호 입력 시 에러

이미 회원가입시 회원가입에 필요한 모델 클래스는 작성했다. 로그인에서는 회원가입 후 가지고 있는 데이터를 가지고 로그인을 하는것이기에 새로운 모델 클래스를 생성할 필요는 없다. 따라서 views.py에 수정사항이 생겼고, 나머지 url에 관련된 부분은 주변 동기들이 멘토님들의 리뷰에 따라서 고치는것을 보고 나도 어차피 고쳐야할 부분이라 생각되서 고친 부분이다.

Views.py

class LoginView(View):
    def post(self, request):
        data = json.loads(request.body)
            
        try:
            if not data['email'] or not data['password']:
                return JsonResponse({'message' : 'No value entered'}, status = 400)
            if User.objects.filter(email = data['email']).exists():
                signin_user = User.objects.get(email = data['email'])
                input_password = data['password']
                if bcrypt.checkpw(input_password.encode('utf-8'), signin_user.password.encode('utf-8')):
                    token = jwt.encode({'user_id' : signin_user.id}, SECRET_KEY, algorithm = 'HS256')
                    # token = jwt.decode(token, SECRET_KEY, algorithm = 'HS256')
                    token = token.decode('utf-8')
                    return JsonResponse({'token' : token}, status = 200)

            return JsonResponse({'message' : 'INVALID_USER'}, status = 401)
        except KeyError:
            return JsonResponse({'message' : 'KEY_ERROR'}, status = 400)

    def get(self, request):
        user = User.objects.values()
        return JsonResponse({'user' : list(user)}, status = 200)

단순히 데이터를 조회하는것에서 끝나는것이 아니라 해당 데이터를 가지고와서 변수에도 넣고, 비교도 해야하기 때문에 post를 사용했다. json 형식의 request를 받아오기 위해서 json.loads를 사용했다.

가장 먼저 구현한 부분은 필수 입력값인 이메일이나 비밀번호가 입력되지 않았을 경우 No value entered 메세지를 반환하며 400 코드를 반환해주도록 했다.

그리고 회원가입 부분과 마찬가지로 JSON KEY 가 잘못 입력됐을 경우KEY_ERROR라는 메세지와 함께 400 에러코드를 반환하는 부분이다. 이 부분은 회원가입에서도 사용한 부분이라서 설명은 생략한다.

다음으로 실제로 데이터를 가지고와서 비교 하는 부분이다. 모델에서 생성한 User 클래스에서 filter() 메소드를 사용해서 이메일에 대한 데이터를 먼저 가져왔다. 비밀번호를 함께 가져오지 않은 이유는 이메일을 먼저 가지고 와서 해당 이메일에 맞는 비밀번호를 비교해야했기 때문이다. 만약 이런 과정이 없었다면 이메일에 맞는 비밀번호가 아닌 다른 비밀번호를 입력해도 로그인이 될 것이다.

filter()를 사용하여 이메일에 관련된 데이터를 가지고 왔다면, User 클래스의 email 데이터를 가지고와서 그 값을 signup_user에 넣어주었다. 이 변수의 패스워드 값을 가지고 와서 데이터에 있는 비밀번호값과 같다면 SUCCESS 메시지와 함께 200 코드를 반환해준다.

만약 비밀번호나 이메일 값을 잘못 입력하면 조건문을 만족하지 않기 때문에 바로 함수의 return단으로 넘어와서 INVALID_USER 메시지와 함께 401 에러코드를 반환한다.


로직에 대해서 틀린부분이 없다고 생각했는데 자꾸 500 에러가 반환됐다. 로그인 함수를 구현하면서 애먹었던 부분은 httpie에 입력한 이메일과 패스워드도 실제 데이터베이스에 저장된 값과 같았다. 한참을 헤매다가 결국 옆의 동기분의 도움을 받아서 문제를 해결할 수 있었다. 에러가 발생했던 기존의 코드는 다음과 같았다.

user = User.objects.all()
 
if user.objects.filter(email = data['email']):
            signup_user = user.objects.get(email = data['email'])

User 클래스에서 모든 데이터를 받아와서 user라는 새로운 변수에 할당했다. 그리고 user 변수에서 이메일 데이터를 불러오려했다. 하지만 아무리 애를써도 되지 않았다. 이런 문제가 발생했던 이유는 내가 objects에 대한 개념이 부족했다.

기존의 User 클래스에는 objects가 내장되어 있어 objects를 사용하여 데이터를 가지고 오는것이 가능했지만 내가 할당한 user에는 objects가 없어서 데이터를 애초에 가지고 올 수가 없던것이였다. 그러다보니 쉘로 직접 확인해보니 쿼리셋에 대한 오류만 주구장창 발생하더라!

Class User

var user

그래서 변수 할당한 부분을 없애고 바로 User.objects로 수정했더니 원했던 결과를 얻을 수 있었다. 에러를 분석하는데도 쉘을 잘 모르니 굉장히 해맸고 도움을 많이 받았다. 쉘에 대한 필요성을 그렇게 느끼지 못했는데, 이번 기회를 통해서 쉘의 중요성을 느끼게 됐다. 로직을 구현했을 때, 마음처럼 동작이 안된다면 실제 데이터는 제대로 저장되어 있는지 쉘을 통해서 분석하면 조금 더 에러의 근본적인 원인에 대해 접근할 수 있는 능력도 길러질 것 같다.


이하 부분은 로그인에 대한 로직에 대한 부분보단 옆의 동기들이 멘토님의 리뷰를 받고 수정한 부분인데 내 코드에서도 수정이 필요한 부분이라 아직 리뷰를 받기 전이지만 함께 수정한 파일들이다.

westagram/urls.py

from django.urls import path , include

urlpatterns = [
    path('User', include('User.urls')),
]

User 앱에 대한 경로를 명확히 지정해주었다.

User/urls.py

from django.urls import path

from .views import SignupView, LoginView

urlpatterns = [
    path('/user', SignupView.as_view()),
    path('/login', LoginView.as_view()),
]

User앱 내에서도 각 기능들에 대한 경로를 지정해주었고, / 를 붙여주었다.

Align

from django.views           import View
from django.http            import JsonResponse
from django.core.exceptions import ValidationError

중구난방으로 작성되어있는 코드는 가독성이 떨어진다. 따라서 import를 기준으로 Align 해주었다.

vim으로 들어가서 : 누르고 Align by import 의 명령어로 정렬시켜줄 수 있다.

추가적인 공부 필요 부분

django shell ( QuerySet )

리뷰 후 수정사항

로그인 관련 클래스에서는 다음과 같은 리뷰를 받았다.

signup_user은 로그인 로직에 있기에 명확한 변수명이 아닙니다. 보다 적절한 변수명으로 수정해주세요

  • 기존 코드
        if User.objects.filter(email = data['email']):
            signup_user = User.objects.get(email = data['email'])
            if signup_user.password == data['password']:
                return JsonResponse({'message' : 'SUCCESS'}, status = 200)

구현을 할 때 signup_user라는 변수 명을 사용한것은 회원가입을 한 유저가 로그인을 하는것이기 때문에 signup_user라는 변수명으로 설정하였다. 리뷰를 받고 나서 생각이 든 것은 회원가입 유저라는 뜻이기 때문에 적절치 못한 것 같다. 보다 명확한 변수명으로 설정하기 위해서는 signin_user라고 칭하는것이 더 어울린다.

( signuped_user 라고 변수명을 만들어도 부적절할지 궁금하다 )

  • 수정 코드
					if User.objects.filter(email = data['email']).exists():
            signin_user = User.objects.get(email = data['email'])
            if signin_user.password == data['password']:
                return JsonResponse({'message' : 'SUCCESS'}, status = 200)

로그인 유저라는 뜻으로 signin_user라고 수정했다.

0개의 댓글