훈훈훈
파이썬(Django) :: 회원 가입 및 로그인 API 구현 본문
장고(Django)를 이용하여 간단하게 회원가입과 로그인 기능을 구현한 API에 패스워드 암호화 및 토큰 기능을 추가해보았다.
* 이전에 구현한 코드
https://wave1994.tistory.com/57
# models.py
models.py 파일은 데이터베이스 테이블을 만들고 그 안의 필드들을 생성 및 수정할 수 있는 역할을 한다.
from django.db import models
class Account(models.Model):
email = models.EmailField(max_length=100, unique=True)
password = models.CharField(max_length=200)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'accounts'
models.py 은 데이터베이스 테이블 생성과 관련 파일이기 떄문에 이전 코드에서 수정한 내역은 없다.
# view.py
view.py은 models.py에서 만든 DB 테이블의 데이터를 처리하는 로직을 만들 수 있다.
이번에 수정한 파일은 view.py이며 해당 파일에 패스워드 암호화 및 토큰 발급 기능을 추가하였다.
- 모듈
import json
import bcrypt
import jwt
from .models import Account
from mysite.settings import SECRET_KEY
from django.views import View
from django.http import HttpResponse, JsonResponse
이전에 작성한 코드에서 추가적으로 bcrypt, jwt 모듈과 외부에 저장해놓은 SECRET_KEY 파일을 임포트하였다.
패스워드를 단방향으로 암호화 하기 위해 bcrypt라는 해시 함수, 그리고 인증(인가)을 위해 JWT(Json Web Token)을 사용하려고 한다.
* SECRET_KEY에 대한 이분은 이전 포스팅한 내용 참고바란다.
- https://wave1994.tistory.com/64
- 클래스
class SignUp(View):
def post(self, request):
data = json.loads(request.body)
try:
if Account.objects.filter(email = data['email']).exists():
return JsonResponse({"message" : "EXISTS_EMAIL"}, status=400)
Account.objects.create(
email = data['email'],
password = bcrypt.hashpw(data["password"].encode("UTF-8"), bcrypt.gensalt()).decode("UTF-8")
).save()
return HttpResponse(status=200)
except KeyError:
return JsonResponse({"message" : "INVALID_KEYS"}, status=400)
위 코드는 회원가입 기능을 하는 클래스이며, 이전 코드에 패스워드 암호화 후 DB에 저장하는 기능을 추가하였다.
패스워드는 UTF-8로 인코딩 후 bcrypt 해시 함수를 이용하여 암호화 후 디코딩 후 DB에 저장하였다. (DB에는 string 값만 저장 가능)
class SignIn(View):
def post(self, request):
data = json.loads(request.body)
try:
if Account.objects.filter(email=data["email"]).exists():
user = Account.objects.get(email=data["email"])
if bcrypt.checkpw(data['password'].encode('UTF-8'), user.password.encode('UTF-8')):
token = jwt.encode({'user' : user.id}, SECRET_KEY, algorithm='HS256').decode('UTF-8')
return JsonResponse({"token" : token}, status=200)
return HttpResponse(status=401)
return HttpResponse(status=400)
except KeyError:
return JsonResponse({'message' : "INVALID_KEYS"}, status=400)
위 코드는 로그인 기능을 하는 클래스이며, 이전 코드에 로그인 성공 시 토큰(JWT)을 발급하는 기능을 추가하였다.
토큰의 페이로드 부분에는 유저의 직접적인 정보를 갖고 있는 이메일이나 이름으로 저장 시, 외부에 노출 위험이 있기 때문에 유저의 PK 값으로 저장하였다.
# urls.py
urls.py 는 파일 명 그대로 경로 (엔드포인트)를 설정할 수 있다. urls.py도 models.py과 동일하게 변경 내역 없이 그대로 사용하였다.
from django.urls import path
from .views import SignUp, SignIn
urlpatterns = [
path('/signup', SignUp.as_view()),
path('/signin', SignIn.as_view()),
# 결과
- 패스워드 암호화
회원 가입 요청 시 아래와 같이 DB에서 패스워드가 암호화가 되어있는 것을 확인할 수 있다.
3|hoon|$2b$12$w6OicdJx.ziWEvtUiQUzHuNFwqeQsh6UNwPK9gcyEnKaLqUu2OEs2|2020-02-14 12:47:22.144974|2020-02-14 12:47:22.150409
4|haha|$2b$12$1mdITD4bJ57S2Ub6KO8.quS5zM2I7SwfKclelglrB2x8x0OQo8J9q|2020-02-15 06:10:04.672130|2020-02-15 06:10:04.675798
6|abcd|$2b$12$VUIxEbEzfC5rkR.5sJTk6unXbDmCuuduhT8gDLIMozmMTgG1Fz0Ru|2020-02-15 12:04:38.956551|2020-02-15 12:04:38.958308
- 토큰 발행
DB에 저장되어있는 ID/PW로 로그인 시 아래와 같이 토큰이 발급되는 것을 확인할 수 있다.
wave@Waveui-MacBookPro http -v localhost:8080/account/signin email=abcd@naver.com password=abcd
POST /account/sign-in HTTP/1.1
Accept: application/json, */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 36
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/2.0.0
{
"name": "abcd@naver.com",
"password": "abcd"
}
HTTP/1.1 200 OK
Content-Length: 114
Content-Type: application/json
Date: Sat, 15 Feb 2020 12:05:09 GMT
Server: WSGIServer/0.2 CPython/3.7.4
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWJjZCJ9.axd08-ceNjMB8koSRzMO1KTSQK3AaO45qJNpka1F74A"
}
* 관련 글
- 간단한 회원가입/로그인 예제
- 회원가입/로그인 + 암호화,토큰
- 회원가입/로그인 입력 값 필터
- 이메일 인증
- 유닛 테스트
'파이썬 > Django' 카테고리의 다른 글
파이썬(Django) :: 장고에 mysql 데이터 베이스 연동하기 (0) | 2020.02.17 |
---|---|
파이썬(Django) :: 인증 데코레이터(Decorator) 클래스 (2) | 2020.02.17 |
파이썬(Django) :: SECRET_KEY 분리 방법 (0) | 2020.02.15 |
파이썬(Django) : 인증(Authentication)과 인가(Authorization) (0) | 2020.02.13 |
파이썬(Django) : 회원가입, 로그인 Simple API 구현 (1) | 2020.02.10 |