import bcrypt
난수 생성 라이브러리 secrets을 이용하여 서버의 서명을 생성한다.
import secrets
print(secrets.token_hex(16))
secrets.token_hex는 인자로 전달한 숫자를 길이로 하는 임의의 hex 문자열을 생성한다.
4비트(16진수) x 16자 = 64비트 = 8바이트
출력되는 랜덤한 키를 Flask 앱을 실행하는 파일
app = Flask(__name__)
app.config["SECRET_KEY"] = '위에서 생성한 서버의 서명'
에 추가한다.
data = request.json()
username = data.get('username')
password = data.get('password')
salt = bcrypt.gensalt() # 임의의 문자열 생성
hashed_password = bcrypt.hashpw(password, salt)
임의의 문자열 salt를 생성해 비밀번호 password와 결합한 뒤 hash하여 만들어진hashed_password를 DB에 저장한다.
data = request.json()
id = data.get('id')
password = data.get('password')
db_pw ## DB에 저장된 비밀번호를 받아온다
password_match = bcrypt.checkpw(password, dbpw)
if password_match:
authkey = secrets.token_hex(16)
## DB에 authkey를 업데이트한다.
login_token = jwt.encode(
{"username": username, "authkey": authkey},
app.config["SECRET_KEY"],
algorithm='HS256'
)
로그인을 요청한 사용자가 DB에 있고 비밀번호가 일치한다는 인증키 authkey를 생성하고, 생성된 인증키를 DB의 User 테이블에 추가한다.
서버는 로그인을 요청한 클라이언트에게 인증키를 전달하고
클라이언트는 서버로 요청을 보낼 때마다 인증키를 함께 보낸다.
인증키와 누구의 인증키인지 표시하는 정보를 함께 PyJWT 라이브러리의 jwt.encode(토큰에 포함할 정보, 서명, 암호화 방법) 암호화하여 login_token으로 만들어 클라이언트에게 보낸다.
클라이언트는 login_token을 받으면 웹브라우저의 세션 스토리지에 저장한다.
window.sessionStorage.setItem("authtoken", responseBody["login_token"]);
클라이언트는 헤더에 authtoken을 담아 POST를 한다.
function onSubmitHandler() {
let headerData = new Headers();
let authToken = sessionStorage.getItem("authtoken");
if (authToken) {
headerData.set("authtoken", authToken);
}
let formData // POST할 내용
fetch('/api/user/authentication', {
method: 'POST',
headers: headerData,
body: formData
}).catch((e) => {
console.log(e);
});
}
서버에서 JWT를 검증한다.
def vefiryJWT(token):
if token:
try:
decoded_token = jwt.decode(token, app.config["SECRET_KEY"], algorithms="HS256")
if decoded_token:
## DB에서 username이 decoded_token['username']과 같은 사용자의 authkey를 받는다
if authkey == decoded_token['authkey']:
return True
except:
pass
return None
로그인 토큰에 포함된 ID와 DB의 ID를 가져온 후 토큰의 인증키값과 ID에 해당하는 사용자의 인증키값을 비교하여 정상적으로 로그인한 사용자인지 판단한다.
function signOutHandler() {
window.sessionStorage.removeItem("authtoken");
window.location.href('/');
}
signout.addEventListener("click", signOutHandler);
프론트엔드에서 세션스토리지의 authtoken을 삭제하면 된다.