앞서서 인증 인가에 대한 개념을 할짝! 했으니 지금은 직접 키보드 뚜드리면서👨💻 몸으로 익히는 TIME
을 가져봐야해요
실습을 위한 가상환경
python venv
혹은 conda env
로 가상환경을 만들게요.
bcrypt pyjwt
요 두개를 pip로 다운받습니다.
pip install bcrypt pyjwt
설치가 완료되었다면 Ipython
을 실행시키고 'bcrypt'를 임포트할게요.
그리고 비밀번호를 해쉬해주는 hashpwd() 함수를 사용하고 rainbow table attack을 막기위해서 salt값을 추가하도록 할게요.
아래 형식의 메소드를 구현해줘야!! -> hash
🎠가 만들어져요.
bcrypt.hashpw( 바이트값, bcrypt.gensalt() )
위 내용 1~4번
더 첨언해볼게요.
b
붙은건 해당 문자열을 byte
로 만들어줘요.파이썬에서 문자열을 바이트로 만드는 방법은 아래와 같이 있어요.
추가 자료 - DelfStack - Convert String to Bytes in Python
b'문자열'
키워드👓'문자열'.encode('utf-8')
👓>>> byte = b'1234'
>>> print(type(byte))
<class 'bytes'>
>>>
>>> byte2 = '1234'.encode('utf-8')
>>> print(type(byte2))
<class 'bytes'>
왜?! byte
값이 아닌 인트라서!
encode()
를 사용하여 -> byte 타입으로 바꿀수 있어요👓byte
-> 문자열로 바꾸려면 'byte'.decode('utf-8')
해주면 되겠주?👓랜덤한 바이트 값들이 계속 나오는걸 확인 할 수 있어요.
>>> bcrypt.gensalt()
b'$2b$12$4utpZCeHmvvIb5QiTTalCO'
>>> bcrypt.gensalt()
b'$2b$12$UENnkg4C.26rJJBZVSx.h.'
>>> bcrypt.gensalt()
b'$2b$12$bSZ8oI3gFA1aGeDxjITcfO'
>>> bcrypt.gensalt()
b'$2b$12$g8l200cGq0zK2ukvD7TDHu'
>>> bcrypt.gensalt()
b'$2b$12$XH8kdj8F8IHeXyGmoxAoDe'
>>> bcrypt.gensalt()
b'$2b$12$cHvrW8GdC9p6VE0zJzlRge'
>>> bcrypt.gensalt()
b'$2b$12$XzJRkFWF5knlwIvDhiXxL.'
>>> bcrypt.gensalt()
b'$2b$12$lR9Y04quIsOko.Hwcf13Tu'
아래 1번에서 gensalt()
로 만든 salt값이 hashpwd()
의 2번째 인자에 둬서 결국 hash_pwd
변수의 값 앞부분에 위치한걸 확인 할수 있조?!
checkpw()
말 그대로 값을 비교하여 True, False
를 반환하는데요. 이때 함수의 인자로는 바이트가 들어갈까요? 아니면 문자열일까요?
2번째줄에 password가 바이트라는거 확인! 그렇다면 7번째줄의 메서드에도 정황상 같은 데이터 타입을 비교할 거라는 예감 오나요?
네! 하지만 해쉬된 바이트로 bycrpt.hashpw()
값 한번 보안처리된 바이트 값이조?
즉!
checkpw(
그냥바이트값
,해쉬된 바이트값
)
이라는 말인거조!
1 >>> import bcrypt
2 >>> password = b"super secret password"
3
4 >>> hashed = bcrypt.hashpw(password, bcrypt.gensalt(14))
5
6
7 >>> if bcrypt.checkpw(password, hashed):
8 ... print("It Matches!")
9 ... else:
10 ... print("It Does not Match :(")
11
위에서 본 bcrypt는 단방향이에요.
즉, 복호화가 불가능에 가깝지만, 이제 살펴볼 JWT
는 Jason Web Token을 복호화하면 Payload
에 암호화하여 담긴 정보를 확인할 수 있어서 사용자가 로그인하면 백엔드 서버가 JWT 토큰을 frontend에 발행하게 되고 프런트앤드는 API를 요청시 request header의 Authorization 키에 access_token을 넣어서 보내면 백엔드 서버는 이 access_token에 담겨있는 header! payload signiture를 확인해서 인가 방법을 제공합니다.
즉, HTTP의 특성인
Stateless
로 인하여 이전 사용자의 로그인을 유무를 알수 없지만 하지만 로그인시에발행한 JWT 토큰 정보를 근거로 백엔드 서버에서는 이 토큰 정보를 해석하는decorator
를 만들어서 인가가 필요한endpoint
들을 사용할 수 있어요.
jwt.encode()
딕셔너리 객체
를 넣어줍니다. SECRET_KEY
인데요. SECRET_KEY
를 끌어다가 사용해요.주의1
jwt.encode(1번째, 2번째, algorithm='HS256')
jwt.decode(1번째, 2번째, algorithms='HS256')
별표 백만개!!!(오류 잡아낸다고 힘들었어요.)😥😣
- encode()는 algorithm이 단수형!
- decode()는 algorithms이 복수형!
주의2
4번째 앞에 b키워드가 없다?
그건 jwt 1.7 -> 2.0 넘어가면서 byte->str으로 타입이 변경되었기 때문에 그래요.
1 >>> import jwt
2 >>> encoded = jwt.encode({'user-id': 5}, "secret", algorithm="HS256")
3 >>> print(encoded)
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzb21lIjoicGF5bG9hZCJ9.Joh1R2dYzkRvDkqv3sygm5YyK8Gi4ShZqbhK2gxcs2U
4 >>> type(encoded_jwt)
<class 'str'>
5 >>> jwt.decode(encoded, "secret", algorithms=["HS256"])
{'user-id': 5}