Westargram with Django 4일차

이번 파트야말로 정말 선배 기수 분들의 블로그 정리가 많이 도움이 되었다. 공부할 겸 거의 카피코딩에 가까운 방식을 사용한 점이 제일 아쉽지만, 결과물을 내꺼로 만들어서 1차 프로젝트 때는 혼자 힘으로 해봐야겠다. 인증인가 자체가 어려워서 자주 반복학습이 필요할 것 같다.

1. 인증 & 인가 간단 정리(아래 코드에 쓰인 개념)

암호화 및 인코딩

  • 먼저 pip로 설치
  • 단방향 알고리즘의 암호화를 검증하는 법 : 입력받은 값을 암호화 해서 저장된 암호화된 값과 비교. 즉 암호화 된 내용끼리의 비교
  • 암호화 전에 utf-8로 인코딩 하는 이유(byte type) : 해싱(암호화, 뭉개짐) 되기 전에 바이트 타입으로 꼭 인코딩을 해줘야 함.
  • 바이트 타입으로는 값을 저장하지 못 한다 -> str으로 다시 디코딩
    바뀐 점
    jwt encode가 현재 byte값이 아닌 바로 str로 나옴.
    따라서 인코딩만 해주면 된다. 따라서 바이트값을 고려할 필요가 없다!

JWT 토큰 생성 :

  • 발행하는 이유 : '인가', 해당 유저의 정보를 얻고 권한도 줄 수 있기 때문에.
  • 먼저 pip로 설치
  • jwt를 import 하여서 토큰 발행
    1) 토큰에 정보 : 유저정보, 시크릿키, 적용하고자 하는 알고리즘
    2) 토큰이 하는 역할 : 제대로 받아온 정보를 확인한 뒤의 과정으로 jwt라이브러리가 데이터를 json body에 담아서 클라이언트에게 다시 보내주는 역할.

인가 절차

  1. 인가 절차를 통해 어세스 토큰을 생성(user_id...)
  2. 유저가 리퀘스트 보낼 때 어세스 토큰을 보낸다.
  3. 서버에서는 유저가 보낸 어세스 토큰을 복호화 한다.
  4. 복호화 된 데이터를 통해 user_id를 얻는다.
  5. user_id 사용해서 데이터베이스 해당 유저 권한을 확인한다.
  6. 유저가 권한 있는지 확인 후 요청 처리 / 에러 보낸다.

2. 코드 및 정리

(코드)
account/views.py

  1. import 섹션
import json
import bcrypt
import jwt

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

from .models     import User
from my_settings import SECRET_KEY

해결하기 위한 선행과제
1) bcrypt, jwt를 모두 설치한다(pip install~)
2) import 해온다.
3) JWT로 서버 간 자유롭게 활용하려면 시크릿키가 필요하므로 시크릿키도 불러온다.

  1. 회원가입 섹션 : 회원가입 시 암호를 암호화하여 데이터베이스에 저장하는 과정
class SignupView(View):
    def post(self, request):
        try:
            data = json.loads(request.body)
            if User.objects.filter(email=data['email']).exists():
                return JsonResponse({"message": "EMAIL_ERROR"}, status=400)
            if User.objects.filter(password=data['password']).exists():
                return JsonResponse({"message": "PASSOWRD_ERROR"}, status=400)
            if '@' in data['email'] and '.' in data['email'] and len(data['password']) >= 8:
            
                byted_password = data['password'].encode('utf-8')
                # 해싱 전 입력하는 패스워드 인코딩
                hash_password = bcrypt.hashpw(byted_password, bcrypt.gensalt()).decode()
                # 사용자가 입력한 값을 해싱하는 과정
                # 마지막에 decode 다시 안 해주면 해싱된 값으로만 저장되어서 로그인 불가능(사용자도 서버도 아무도 몰라..)
                password = hash_password
                user     = User.objects.create(
                email    = data['email'],
                password = password
                # 위에서 이미 패스워드 해쉬 해버림
            )
            # 값 세이브 필요 없어서 지움
                return JsonResponse({"message": "SUCCESS"}, status=200)
            return JsonResponse({"message":"MAKE_FAIL"}, status=400)
        except KeyError:
            return JsonResponse({"message": "KEY_ERROR"}, status=400)
  1. 로그인 섹션 : 딱 로그인 하는 부분
class LoginView(View):
    def post(self, request):
        try:
            data = json.loads(request.body)
                user = User.objects.get(email=data['email'])
                # 유저는 이메일 데이터로 가져오고(1:1매칭이므로) 
                if bcrypt.checkpw(data['password'].encode('utf-8'), user.password.encode('utf-8')):
                # 만일 인코딩 된 패스워드와 저장된 패스워드 데이터가 동일하다면
                 
                    token = jwt.encode({'email' : data['email']}, SECRET_KEY, algorithm="HS256")
                    # 토큰에 정보 : 유저정보, 시크릿키, 적용하고자 하는 알고리즘 발행
                    # 클라이언트에게 이메일 부분을 암호화 하여 보내줌.(by json body)
                    # 클라이언트는 헤더에 토큰을 담아서 보내줘야 함.
                    # h5yp 버전 문제로 디코드 안 해도 됨.
                    
                    '''(인가 절차)
                    1. 인가 절차를 통해 어세스 토큰을 생성(user_id...)
                    2. 유저가 리퀘스트 보낼 때 어세스 토큰을 보낸다.'''
                
                return JsonResponse({"message":"SUCCESS"}, status=200)
                '''(인가 절차)5. user_id 사용해서 데이터베이스 해당 유저 권한을 확인한다.
                6. 유저가 권한 있는지 확인 후 요청 처리 / 에러 보낸다.'''
            else:
                return JsonResponse({"message":"INVALID_USER"}, status=401)
        except KeyError:
            return JsonResponse({"message":"KEY_ERROR"}, status=400)
  1. 토큰 체크 뷰 : 인가된 사용자인지 아닌지 최종 확인. 즉 앞서 로그인 한 사용자를 지속적으로 확인하는 로직.
class TokenCheckView(View):
    def post(self,request):
        data = json.loads(request,body)
        
        user_token_info = jwt.decode(data['token'], SECRET_KEY, algorithms='HS256')
        # 받아온 유저의 정보는 jwt 라이브러리로 토큰 값을 디코드 하여 원래 유저와 같은지 비교
        '''(인가 절차) 3. 서버에서는 유저가 보낸 어세스 토큰을 복호화 한다.
        4. 복호화 된 데이터를 통해 user_id를 얻는다.'''
        
        if User.objects.filter(email=user_token_info['email']).exists():
            return JsonResponse({"message": "SUCCESS"}, status=200)
            # 리턴된 유저 정보가 데이터와 동일하면 성공
            # (인가절차)5. user_id 사용해서 데이터베이스 해당 유저 권한을 확인한다.
        return JsonResponse({"message":"INVALID_USER"}, status=401)
        인가되지 않으면 실패
        # (인가 절차) 6. 유저가 권한 있는지 확인 후 요청 처리 / 에러 보낸다.

3. 생각해볼거리

  1. 추후 TokenCheckView부분은 데코레이터로 자동화 해줘야 한다고 함.
  2. 전체적인 플로어 익숙해지기
  3. 선배 블로그 등 다른 다양한 경우를 보지 않고도 할 수 있는 역량 기르기(중요)
  4. 인증인가 익숙해지기

참고 블로그

profile
커피 내리고 향 맡는거 좋아해요. 이것 저것 공부합니다.

0개의 댓글