인증(authentication)이란 클라이언트가 사용자의 아이디와 비밀번호 등을 확인하여 요청을 진행하는 대상을 검증 및 보호하는 것입니다. 인가(authorization)란 해당 인증을 마친 사용자에게 특정한 권한을 부여하는 것입니다. 예를 들어, 웹사이트에 로그인하는 것은 인증이고, 이를 통해 댓글을 작성할 수 있게 되는 것은 인가에 해당합니다.
인증: bcrypt 설치 및 암호화, 검증 방법
bcrypt는 암호를 해싱해주는 라이브러리입니다. 입력된 값을 단방향 해싱하기 때문에 복호화는 불가능합니다.
- bcrypt를 설치합니다.
pip install bcrypt
- 파이썬 인터프리터 실행 후 임포트를 진행합니다.
import bcrypt
- 암호화를 진행하려면
hashpw
메소드를 사용합니다. bcrypt를 통해 암호화를 진행하려면Bytes
데이터가 필요합니다. 파이썬에서는str
을 인코딩하면Bytes
가 되고,Bytes
를 디코딩하면str
이 됩니다. 따라서 입력된 패스워드를 암호화하려면 이를 인코딩해야 합니다.
password='1234'
type(password)
#<class 'str'>
encoded_password = password.encode('utf-8')
type(encoded_password)
#<class 'bytes'>
password
를 인코딩하여 바이트로 전환한 후 해시했다면,gensalt
를 사용하여 암호화를 강화할 수 있습니다.
password = '1234'
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
print(hashed_password)
#b'$2b$12$YFs9rh.1LgJwZuf9ibyjpuLvBoCaGX0MzedFWF2Jo0zU3lMZurZ4a'
print(type(hashed_password))
#<class 'bytes'>
gensalt
는 랜덤하게 생성되는 해시입니다.
bcrypt.gensalt()
#b'$2b$12$JxMoALbxtOr5t7fpMSbGfO'
bcrypt.gensalt()
#b'$2b$12$f7gaCJnuRX9XGNh8g3hSDe'
- 그렇다면 차후 어떻게 비밀번호 일치 여부를 확인할 수 있을까요? 해시된 비밀번호에는
gensalt
값이 함께 저장되어 있습니다! 비밀번호를 확인하려면checkpw
메소드를 사용합니다.
new_password = '1234'
bcrypt.checkpw(new_password.encode('utf-8'), hashed_password)
#True
- 기존의 회원가입 views.py에서 이를 활용하면 다음과 같이 사용자가 입력한 패스워드를 암호화하여 데이터베이스에 저장할 수 있습니다. 해싱은 인코딩을 진행해야 하지만, 이를 데이터베이스에 추가할 때는 디코딩하여 전달해주어야 합니다.
import json
import bcrypt
from django.shortcuts import render
from django.http import JsonResponse
from django.http.response import HttpResponse
from django.views import View
from django.core.exceptions import ValidationError
from django.db.utils import IntegrityError
from .models import User
from .validators import is_email_valid, is_password_valid
class RegisterView(View):
def post(self, request):
data = json.loads(request.body)
try:
name = data["name"]
email = data["email"]
password = data["password"]
contact = data["contact"]
note = data["note"]
is_email_valid(email)
is_password_valid(password)
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
user = User.objects.create(
name = name,
email = email,
password = hashed_password.decode('utf-8'),
contact = contact,
note = note
)
return JsonResponse({"message": "SUCCESS"}, status=201)
except KeyError:
return JsonResponse({'message': "KEY_ERROR"}, status=400)
except IntegrityError:
return JsonResponse({'message': "INTEGRITY_ERROR"}, status=400)
except ValidationError as e:
return JsonResponse({'message': f"{e.message}"}, status=401)
인가: JWT를 사용한 토큰 발급 및 확인 방법
- JWT는 JSON Web Token의 약자입니다. 먼저, PyJWT 라이브러리를 설치합니다.
pip install pyjwt
- 파이썬 인터프리터 실행 후 임포트를 진행합니다.
import jwt #패키지 인스톨 시에는 pyjwt이지만 임포트 할 때는 jwt
- JWT에서 토큰(access_token)을 생성합니다.
SECRET = 'password'
access_token = jwt.encode({'id':1}, SECRET, algorithm='HS256')
print(access_token)
# eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.-xXA0iKB4mVNvWLYFtt2xNiYkFpObF54J9lj2RwduAI
- 발급된 토큰을 통해 사용자 인증을 진행할 수 있습니다.
header = jwt.decode(access_token, SECRET, algorithms='HS256')
print(header)
# {'id':1}
- 이를 활용하여 토큰 발행, 확인을 진행할 수 있습니다.
import json
import bcrypt
import jwt
from django.shortcuts import render
from django.http import JsonResponse
from django.http.response import HttpResponse
from django.views import View
from django.core.exceptions import ValidationError
from users.models import User
from my_settings import SECRET_KEY, ALGORITHM
class LoginView(View):
def post(self, request):
data = json.loads(request.body)
try:
email = data["email"]
password = data["password"]
user_email = User.objects.get(email=email)
if not user_email:
raise ValidationError("INVALID_USER")
validating_password = bcrypt.checkpw(password.encode('utf-8'), user_email.password.encode('utf-8'))
if not validating_password:
raise ValidationError("INVALID_PASSWORD")
access_token = jwt.encode({'id': user_email.id}, SECRET_KEY, algorithm=ALGORITHM)
def decoding_access_token(access_token, SECRET_KEY):
payload = jwt.decode(access_token, SECRET_KEY, algorithms=ALGORITHM)
return payload
user_information = decoding_access_token(access_token, SECRET_KEY)
return JsonResponse({'message': f"SUCCESS, USER TOKEN: {access_token}, USER INFORMATION: {user_information}"}, status=200)
except KeyError:
return JsonResponse({'message': "KEY_ERROR"}, status=400)
except ValidationError as e:
return JsonResponse({'message': f"{e.message}"}, status=401)
- JWT에 관련해 더 읽어볼 글: JWT란 정확히 무엇이며 왜 사용할까?, JWT 토큰 유효시간
반응형
'Django' 카테고리의 다른 글
장고 프론트엔드와 통신 방법: HTTP POST, GET request 처리하기 (0) | 2022.01.28 |
---|---|
장고 추상 모델 클래스 생성과 상속 방법 (0) | 2022.01.21 |
장고 HTTP 리퀘스트 유효성 검사 및 에러 메시지 작성 방법 (0) | 2022.01.16 |
장고 데이터 모델 작성과 CRUD 테스트 방법 (0) | 2022.01.11 |
장고 URL 추가 및 Views에서 URLconf 요청 응답 처리 방법 (0) | 2022.01.10 |