파이참으로 첫 번째 프로젝트를 만들면서 필수과제인 JWT를 이용하여 회원가입과 로그인을 구현하였다.
회원가입 시 비밀번호를 해쉬값으로 변환하여 DB에 저장하여 해쉬값이 유출되더라도 비밀번호를 알 수 없도록 하게 했다.
@app.route('/sign_up/save', methods=['POST'])
def signup_save():
id_receive = request.form['id_give']
password_receive = request.form['password_give']
nickname_receive = request.form['nickname_give']
password_hash = hashlib.sha256(password_receive.encode('utf-8')).hexdigest()
doc = {
"id": id_receive, # 아이디
"password": password_hash, # 비밀번호
"nickname": nickname_receive, # 프로필 이름 기본값은 아이디
}
db.users.insert_one(doc)
return jsonify({'result': 'success'})
메인 페이지에서는 jwt 토큰이 없으면 웹페이지의 콘텐츠를 이용할 수 없게 하여 필수로 회원가입과 로그인을 하게 하였다.
jwt토큰은 'my token'이라는 이름으로 쿠키값으로 저장되게 만들었으며 쿠키값을 알더라도 SECRET_KEY를 모르면 복호화가 불가능하게 하였다.
@app.route('/', methods=["GET"])
def home():
token_receive = request.cookies.get('mytoken')
try:
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
return render_template('index.html',token=token_receive)
except jwt.ExpiredSignatureError:
return render_template('index.html')
except jwt.exceptions.DecodeError:
return render_template('index.html')
로그인 시 사용자가 적은 아이디와 비밀번호를 가져와 비밀번호를 해쉬값으로 변환한 후 DB와 비교하여 유저라면 아이디 값을 이용하여 쿠키를 발행해주고 유저가 아닐 시 아이디와 비밀번호가 일치하지 않는다는 메시지를 클라이언트에 주도록 하였다.
@app.route('/sign_in', methods=['POST'])
def sign_in():
# 로그인
id_receive = request.form['id_give']
password_receive = request.form['password_give']
pw_hash = hashlib.sha256(password_receive.encode('utf-8')).hexdigest()
result = db.users.find_one({'id': id_receive, 'password': pw_hash})
if result is not None:
payload = {
'id': id_receive,
'exp': datetime.utcnow() + timedelta(seconds=3600) # 로그인 24시간 유지
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
print(token)
return jsonify({'result': 'success', 'token': token})
# 찾지 못하면
else:
return jsonify({'result': 'fail', 'msg': '아이디/비밀번호가 일치하지 않습니다.'})
클라이언트에서 서버에 쿠키값을 보내면 쿠키값을 복호화하여 유저 정보를 알아낸 후 그 유저 정보를 활용해 DB에 원하는 정보를 저장하게끔 함으로써 개인정보보안에 더 힘쓰었다.
@app.route('/quiz/savetime', methods=['POST'])
def quiz_savetime():
time_receive = request.form['time_give']
cookie_receive = request.form['cookie_give']
review_receive = request.form["review_give"]
print(cookie_receive)
id = jwt.decode(cookie_receive, SECRET_KEY, algorithms='HS256')["id"]
user = db.users.find_one({'id': id})
doc = {
"nickname": user["nickname"],
"totaltime": int(time_receive),
"review": review_receive
}
db.ranking.insert_one(doc)
return jsonify({'result': 'success'})
로그인 시 이러한 오류가 발생했었는데 파이썬 패키지중인 하나인 PyJWT의 버전 차이로 인해 발생한다는 이유를 알게 되었다. 이러한 이유가 발생한다면 아래의 그림처럼 수정하거나 PyJWT의 버전을 바꿔본다면 오류가 없어질 것이다.
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256').decode('utf-8')
오류가 일어난 코드
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
수정 후 코드
그리고 서버와 클라이언트의 모든 통신은 REST API를 이용하여 통신하였다. REST API에서 GET과 POST를 이용하여 구현하였는데 GET은 서버에서 데이터를 받아올 때 사용하였고 POST는 서버의 데이터를 변경할 때 사용하였다. 로그인 시 GET과 POST를 어떤 것을 사용할지 고민이 있었는데 인터넷에 검색해본 결과 URL이 남지 않는 POST가 안전하다고 하여 POST로 통신하였다.
function sign_in() {
let id = $("#input-id").val()
let password = $("#input-password").val()
if (id == "") {
$("#help-id-login").text("아이디를 입력해주세요.")
$("#input-id").focus()
return;
} else {
$("#help-id-login").text("")
}
if (password == "") {
$("#help-password-login").text("비밀번호를 입력해주세요.")
$("#input-password").focus()
return;
} else {
$("#help-password-login").text("")
}
$.ajax({
type: "POST",
url: "/sign_in",
data: {
id_give: id,
password_give: password,
},
success: function (response) {
if (response['result'] == 'success') {
$.cookie('mytoken', response['token'], {path: '/'});
window.location.replace("/")
} else {
alert(response['msg'])
}
}
});
}
로그인 시 POST를 이용한 RESTAPI통신
'WIL' 카테고리의 다른 글
이노베이션 캠프 6주차 WIL (0) | 2022.07.31 |
---|---|
이노베이션 캠프 5주차 WIL (0) | 2022.07.24 |
이노베이션 캠프 4주차 WIL (0) | 2022.07.17 |
이노베이션캠프 3주차 WIL (0) | 2022.07.10 |
이노베이션캠프 2주차 WIL (0) | 2022.07.03 |