First Toy Proejct-2[Westagram][20210828]

Jungsoo kim·2021년 8월 29일
0

wecode

목록 보기
17/30

지난 글에 이어 Toy Project에 대해 조금 더 블로깅 해보려고 한다.

<목차>
1. 로그인 기능 구현
2. 회원가입 비밀번호 암호화 & 로그인 시 JWT 발행
3. 마무리

1. 로그인 기능 구현

사실 이번에 진행한 Toy project에는 회원가입 기능과 로그인 기능의 큰 차이가 없다... 회원가입 때와 마찬가지로 터미널에서 Post 메서드를 사용하서 데이터를 보내주면 Mysql 데이터 베이스에 해당 데이터가 있는지 확인만 하는 기능 정도이다. 추가로 간단하게 구현한 기능은 아래와 같다.

  • 로그인 시 확인하는 데이터는 이메일과 패스워드이다.
  • 계정이나 패스워드를 입력하지 않았을 경우, {"message": "KEY_ERROR"}, status code 400 메세지 반환
  • 계정 or 패스워드를 잘못 입력했을 경우, {"message": "INVALID_USER"}, status code 401 메세지 반환

이에 대한 코드는 아래와 같다.

class LogInView(View):
    def post(self, request):
        data = json.loads(request.body)

        try:
            email    = data['email']
            password = data['password']
            
            if User.objects.filter(email = data['email']).exists():
                user_email = User.objects.get(email = data['email'])
                if bcrypt.checkpw(password.encode('utf-8'), user_email.password.encode('utf-8')):
                    token = jwt.encode({'id' : user_email.id}, SECRET_KEY, algorithm='HS256')
                    return JsonResponse({"message" : "SUCCESS", "token" : token}, status = 200)
                return JsonResponse({"message" : "INVALID_USER"}, status = 401)
            return JsonResponse({"message" : "INVALID_USER"}, status = 401)
        except KeyError:
            return JsonResponse({"message" : "KEY_ERROR"}, status = 400)

사실 위의 코드는 아래 4번에서 서술할 예정인 JWT 기능까지 구현한 코드이다. 참고하기 바란다.

회원가입 기능 구현때와 마찬가지로 터미널에서 입력된 데이터를 json.load 기능을 통해 Json타입으로 가져온 후에 변수에 할당해주고, 할당된 변수의 데이터가 데이터 베이스에 있는지를 확인 하는 과정을 거친다.

위에서 보면 에러 메시지를 반환 할 때 이메일 계정이나 패스워드를 잘못 입력하였을 때는 401번 에러로 반환하고 아예 입력을 하지 않은 경우는 400번 에러로 반환하였다.
간단하게 두 가지 에러 코드의 차이를 짚고 넘어가자면, 400번 에러는 요청 자체가 잘못되었다는 의미이며, 401번 에러는 요청은 제대로 되었으나 권한이 올바르지 않아서 다음 단계로 넘어갈 수 없다는 의미 정도로 보면 될 것 같다.

덧붙여, 앞서 회원가입 기능 구현 시에 urls.py 작성에 관련한 내용을 빼먹었다. 그 내용에 대해서 여기서 덧붙여 이야기 하려고 한다.

Django의 경우에는, 컴퓨터가 서버에 접근하려고 할 때, IP주소를 통해 명령을 입력받게 되는데 입력된 명령이 바로 views.py로 가는 것이 아니라 프로젝트 폴더에 있는 urls.py로 먼저 명령이 입력되며 그 이후에 views.py로 전달 된다.

따라서, urls.py에서 views.py로 접근이 가능하게 끔 경로 설정을 해줘야 한다. 프로젝트 폴더를 생성하게 되면 저절로 urls.py 파일이 생성된다. 그러나 이것은 프로젝트 전체의 경로 설정을 하는 파일이며, 개별 애플리케이션의 기능에 접근하기 위해 경로를 설정해 주러면 애플리케이션 고유의 urls.py 파일이 있어야 한다.

따라서, 생성한 애플리케이션 폴더에 urls.py파일을 새로 생성해 준다.

생성 후의 폴더의 경로는 아래와 같다.

여기서 westagram는 프로젝트 폴더이며 이 폴더 안에 있는 urls.py는 메인 경로를 위한 파일이다.
users는 애플리케이션 폴더이며 이 폴더 안에 있는 urls.py는 회원가입 & 로그인 기능을 위한 경로가 있는 파일이다.

각 urls.py 안에 적혀져 있는 코드는 아래와 같다.

# westagram 프로젝트 메인 urls.py

from django.urls import path, include

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

프로젝트에 접근 가능한 URL의 메인 경로를 users로 해준다는 의미이며, users.urls와 연결을 해주겠다는 것이다.

# users 애플리케이션 urls.py
from django.urls import path

from users.views import UserView, LogInView

urlpatterns = [
    path('/user', UserView.as_view()),
    path('/login', LogInView.as_view()), 
]

메인 urls.py를 통해 명령을 전달 받을 때 users/user 경로로 받게 되면 회원가입 기능 구현 views.py를 실행하며, users/login 경로로 받게 되면 로그인 기능 구현 vies.py를 실행하게 된다는 의미로 보면 된다.

따라서, 지금은 로그인 기능을 확인하고 싶기 때문에 터미널에서 users/login 경로로 명령어를 입력해주면 된다.

$ http -v POST 127.0.0.1:8000/users/login email='seongchul91@naver.com' password='1234qwer!Q'

이미 JWT 발행하는 기능을 구현한 상태라 위의 사진과 같이 로그인과 동시에 token이 발행되는 것을 확인 할 수 있다.

2. 회원가입 비밀번호 암호화 & 로그인 시 JWT 발행

앞서, 간단한 회원가입 기능과 로그인 기능을 구현해봤다. 이제 비밀번호 암호화 기능과 JWT(Json Web Token)을 발행하는 기능을 추가로 덧붙이려 한다.

우선 이 두 가지의 기능을 왜 하는지를 먼저 알아봐야 할 것 같은데, 이유는 아래와 같다.

비밀번호 암호화

  비밀번호의 경우에는 중요한 개인정보이기 때문에, 설령 외부에서 데이터베이스로 접근하더라도 비밀번호가 어떤 것인지 알 수 없게 해야한다. (법적으로 암호화해서 보관해야 된다.)
이런 이유들 때문에 보통의 사이트에서 비밀번호를 잊어버렸을 경우 비밀번호 찾기를 할 때, 비밀번호를 알려주는 것이 아니라 새로운 비밀번호를 저장하라고 하는 것이다.(사이트 관리자도 비밀번호가 무엇인지 알 수 없다.)

JWT

  웹사이트에서 인가가 필요한 기능 요청이 올 경우, 요청자가 권한이 있는지 없는지의 여부확인이 필요하다. 근데 이런 요청이 올 때마다 로그인을 요청하는 것은 사용자 입장에서는 아주 불편하다. 그래서 최초 로그인 시에 JWT라는 것을 발행해서 사용자에게 준다. 그 후 인가가 필요한 요청을 사용자가 할 때, 발행 된 JWT를 통해 요청한 사용자가 권한이 있는지 여부를 확인 한다.

비밀번호 암호화 기능과 JWT발행을 위한 코드는 아래와 같다.

import json
import re
import bcrypt
import jwt

from django.views import View
from django.http import JsonResponse

from users.models import User
from my_settings import SECRET_KEY

# 비밀번호 암호화

User.objects.create(
                name         = data['name'],
                email        = data['email'], 
                password     = bcrypt.hashpw(data['password'].encode('utf-8'), bcrypt.gensalt()).decode('utf-8'),
                phone_number = data['phone_number'], 
                address      = data['address'], 
            )
            return JsonResponse({"message" : "SUCCESS"}, status = 201)

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
# JWT 발행 기능

user_email = User.objects.get(email = data['email'])
if bcrypt.checkpw(password.encode('utf-8'), user_email.password.encode('utf-8')):
                    token = jwt.encode({'id' : user_email.id}, SECRET_KEY, algorithm='HS256')
                    return JsonResponse({"message" : "SUCCESS", "token" : token}, status = 200)

우선, 비밀번호 암호화 기능인 bycrpt를 사용하기 위해서는 bycrpt를 import 해줘야하며, jwt도 마찬가지로 import 해줘야 한다.

코드를 살펴보면, 회원가입 시 입력된 정보를 기반으로 데이터베이스에 등록을 하게 되는데 password항목만 다른 항목들과 코드가 다른 것을 볼 수 있다.
이는 bcrypt 명령어를 사용해서 암호화 하는 과정이 포함되어 있기 때문인데, 간략히 설명하자면 입력 받은 데이터를 먼저 인코딩을 하고 일련의 방식을 통해 암호화 한다. 그 후에 다시 디코딩 된 정보를 저장한다.
암호화를 하기위해서는 데이터를 인코딩해줘야 하기 때문에 인코딩을 하고 데이터 저장시에는 디코딩 된 데이터를 저장하는게 좋기 때문에 다시 디코딩 하는 과정을 거친다.
이에 대한 설명은 다음 블로그에서 자세히 다룰 예정이다.

다음으로 jwt발행에 대한 코드를 살펴보면, 입력 받은 password 값을 인코딩 한 것과 데이터베이스에 저장되어 있는 password를 인코딩 한 것이 같을 경우 성공 메시지와 함께 토큰을 사용자에게 알려준다.

참고로, 첫번째 줄의 코드는 입력 받은 계정정보(email)를 통해 get 메서드를 사용하여 특정된 queryset을 user_email이라는 변수에 할당 한 것이다.

위의 과정을 거치면, 회원가입을 진행하였을 때 데이터베이스에 저장되는 정보는 아래의 사진과 같다.

마지막으로, 로그인 시 jwt가 발행되는 것은 아래와 같이 확인 할 수 있다.

3. 마무리

  이번 글에서는 로그인 기능, 비밀번호 암호화, jwt발행을 어떻게 하는지에 대해 간단하게 알아보았다. 그러나, 인증 & 인가에 대한 내용에 대해서는 깊게 다루지 않았는데, 이는 앞서 말했던 것과 같이 다음 글에서 따로 심도있게 다뤄봐야 할 것 같다. 그럼 이만...

profile
어렵지만 꾸준히 차근차근 해 나가자~!

0개의 댓글