<로그인 flow>
1) 유저 로그인 -> 아이디와 비밀번호 입력
2) 유저가 입력한 비밀번호 암호화 한후 암호화되서 DB에 저장된 유저 비밀번호와 비교
3) 일치하면 로그인 성공
4) 로그인 성공하면 access tocken을 클라이언트에게 전송
5) 유저는 로그인 성공 후 다음부터는 access token을 첨부해서 request를 서버에 전송함으로서 매번 로그인 해도 되지 않도록 한다.
class LoginView(View):
def post(self, request):
try:
data = json.loads(request.body)
email = data.get('email')
nickname = data.get('nickname')
phone_number = data.get('phone_number')
if email or nickname or phone_number:
if not User.objects.filter(Q(email=email) | Q(nickname=nickname) | Q(phone_number=phone_number)).exists():
return JsonResponse({'MESSAGE': 'NOT FOUND'}, status=404)
passwords = User.objects.get(email=data['email']).password
if bcrypt.checkpw(data['password'].encode('utf-8'),passwords.encode('utf-8')):
access_token = jwt.encode({'id': User.objects.get(email=email).id}, SECRET['secret'], algorithm='HS256')
return JsonResponse({'MESSGAGE': access_token}, status=200)
else:
return JsonResponse({'MESSAGE': 'NOT FOUND'}, status=404)
except KeyError:
return JsonResponse({'MESSAGE': 'KEY_ERROR'}, status=400)
💡 로그인
로그인을 할때 email, nickname, phone_number 중 하나만 들어와도 로그인이 되도록 구현하는 것이필요 했다. 근데 단순히 if email = ''
이런식으로 값이 안들어 와도 된다! 라는 생각을 갖고 만드니깐 keyerror문제가 발생해서 엄청 애먹었다. 이후 dict.get('key')을 사용하면 된다는 사실을 알게 되었다.
email = data.get('email')
nickname = data.get('nickname')
phone_number = data.get('phone_number')
이런식으로 데이터를 받으면 데이터가 없어면 그냥 None이 들어오기때문에 keyerror 오류 해결이 가능했다.
💡 토큰 발행
나는 프론트랑 통신할때 email만 입력해서 로그인이 될 수 있도록 생각하고 코드를 짜서 email이 동일한 사람의 id를 가져온다고 생각했다. 그리고 secret_key도 다른 파일에 secret key를 딕셔너리 형태로 선언해두고 import 해서 사용했기 때문에 SECRET['secret']
이런식으로 써주었다.
secret_key는 토큰 발행을 위해 encode할때랑 그 토큰을 다시 decode할때의 secret_key가 동일 해야 한다.
.filter()
쿼리셋 형태로 가져온다.
filter(name='지원') <이름이 지원인 애만 가져옴..!>
name은 데이터베이스의 컬럼명!!!
=> 무조건 쿼리(object)로 바꿔야 데이터를 찾아올 수 있다.
email = data.get('email')
얘는 키가 있으면 가져오고 없으면 default 값을 가져옴 (무조건 값이 들어오게 되어있다.-> 없으면 default 값이라도 들어오니깐)
email = data['email']
얘는 무조건 key명인 email의 value가 있어야 됨.
key가 없으면 아예 eamil이라는 변수에 값이 안들어가면서 에러가 난다. (KEYERROR)
로그인 할때는 nickname, email, phone_number중 하나가 들어오면 로그인이 되어야 한다.
data.get('email')는 default 값이라도 들어오니깐 괜찮은데 data['email']은 email이라는 key가 없을때 아무 value도 들어오지 않으니깐 keyerror가 발생한다.
토큰
백엔드 입장에 토큰은 어떤 유저 정보를 담아서 보내주어야 하는지 알기 위해서 필요한것이다.
예를 들어서 백엔드는 어떤 유저가 로그인을 했는지 알지 못하는 상태이다. 그러니깐 token을 통해서 어떤 유저의 장바구니를 보여주고, 마이페이지를 보여줄지 알수 있다.
프론트에서 request마다 토큰을 보내준다. (로그인한 상황이 필요할때 마다)
프론트는 토큰을 로컬스토리지에 담는다.
else 덜 쓰는 팁은 안되는 경우부터 먼저 생각하면 더 쉽다.
jwt로 토큰 발행하는 방법
import jwt #패키지명은 pyjwt이지만 임포트할때의 이름은 jwt입니다.
SECRET = 'secret' #'랜덤한 조합의 키' 예제이므로 단순하게 'secret'이라고 하겠습니다.
token = jwt.encode({'id': User.objects.get(email=email).id}, SECRET, algorithm='HS256')
print(access_token)
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.-xXA0iKB4mVNvWLYFtt2xNiYkFpObF54J9lj2RwduAI'
header = jwt.decode(access_token, SECRET, algorithm = 'HS256')
print(header)
{'id': 1}
백엔드가 담아서 넘기는 headers 값을 통해 유저를 식별할 수 있다.
프론트는 유저의 정보를 headers에 담아서 request를 보낸다.
백엔드는 처음에 토큰을 생성하고 로그인할때 딱 한번만 보내주고, 그 다음부터는 프론트가 항상 http의 header에다가 토큰을 담아서 백엔드에게 request한다. 그리고 백엔드는 그 토큰을 기준으로 유저가 누구인지 판별할 수 있게 해준다.
이것을 인증하는 코드는 데코레이터로 구현한다.