7. 봉드로이드_개발공부
회원 로그인 기능을 만들어보자! (쿠키값 생성 및 유지 - ft. JWT 토큰)
마켓플레이어, 마케터 봉
2024. 10. 28. 11:47
회원 가입 시 암호화 했으니, 그 암호화된 pw와 id로 회원정보를 찾아야한다.
https://marketerbong.tistory.com/90
로그인 기능은 간단하다.
회원가입 시 입력한 id(이메일)과 pw(암호화)로 일치하는 정보를 찾고, 불러오면 된다.
다만 주의할 점은 로그인이 유지 되려면 토큰을 생성해 같은 사람임을 인식하도록 해야한다. (쉽게 말해서 쿠키값이 남아있을 때까지 로그인이 되는 것이다.)
우선 파이썬 파일을 만들었다.
순서는 다음과 같다. 회원가입 때와 같은 방법으로 pw를 암호화해서 일치하는 정보를 찾고, 찾았으면 jwt 토큰을 만들어 발행한다.
from flask import Flask, render_template, request, jsonify, Blueprint
from pymongo import MongoClient
import certifi
import jwt
import datetime
import hashlib
bp = Blueprint("login", __name__, template_folder="templates")
ca = certifi.where()
client = MongoClient("mongodb+srv://몽고디비아이디:패스워드@cluster0.hecgbmx.mongodb.net/Cluster0?retryWrites=true&w=majority", tlsCAFile = ca)
db = client.bongdroid
SECRET_KEY = 'password'
@bp.route('/')
def loginCall():
return render_template('login.html')
# 로그인
@bp.route('/', methods=['POST'])
def api_login():
email_receive = request.form['email_give']
password_receive = request.form['password_give']
# 회원가입 때와 같은 방법으로 pw를 암호화합니다.
password_hash = hashlib.sha256(password_receive.encode('utf-8')).hexdigest()
# id, 암호화된pw을 가지고 해당 유저를 찾습니다.
result = db.user.find_one({'email': email_receive, 'password': password_hash})
# 찾으면 JWT 토큰을 만들어 발급합니다.
if result is not None:
# JWT 토큰 생성
payload = {
'email': email_receive,
'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=86400)
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
# token을 줍니다.
return jsonify({'result': 'success', 'token': token})
# 찾지 못하면
else:
return jsonify({'result': 'fail', 'msg': '아이디/비밀번호가 일치하지 않습니다.'})
# 보안: 로그인한 사용자만 통과할 수 있는 API
@bp.route('/isAuth', methods=['GET'])
def api_valid():
token_receive = request.cookies.get('mytoken')
try:
# token을 시크릿키로 디코딩합니다.
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
# payload 안에 id가 들어있습니다. 이 id로 유저정보를 찾습니다.
userinfo = db.user.find_one({'email': payload['email']}, {'_id': 0})
if userinfo:
return jsonify({'result': 'success', 'name': userinfo['name'], 'email': userinfo['email']})
else:
return jsonify({'result': 'fail', 'msg': '로그인 정보가 존재하지 않습니다.'})
except jwt.exceptions.ExpiredSignatureError:
# 위를 실행했는데 만료시간이 지났으면 에러가 납니다.
return jsonify({'result': 'fail', 'msg': '로그인 시간이 만료되었습니다.'})
except jwt.exceptions.DecodeError:
# 로그인 정보가 없으면 에러가 납니다!
return jsonify({'result': 'fail', 'msg': '로그인 정보가 존재하지 않습니다.'})
참고로 아래 내용은 UTC(협정 세계시)로 현재 시간을 가져오라는 의미다.
datetime.datetime.utcnow()
그리고 아래 내용은 86400초, 즉 24시간 동안 유지하기 위해 위 UTC 에 86400초를 더한 시간을 exp로 정했다.
datetime.timedelta(seconds=86400)
html 파일은 다음과 같다.
입력된 id와 pw를 가져와서 일치하면, 토큰을 쿠키에 저장하고, 로그인 완료 얼럿창을 띄운 후 메인페이지로 이동하게 했다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
<script src="http://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>
<link rel="stylesheet" href="/static/css/font.css">
<link rel="stylesheet" href="/static/css/login.css">
<script>
function loginCall() {
$.ajax({
type: "POST",
url: "/login/",
data: {
email_give: $('#email').val(),
password_give: $('#password').val(),
},
success: function (response) {
if (response['result'] == 'success') {
// 로그인에 성공하면 token을 쿠키에 저장!!!!
$.cookie('mytoken', response['token'], { path: '/' });
alert('로그인 완료!')
window.location.href = '/'
} else {
alert(response['msg'])
}
}
})
}
</script>
<title>로그인</title>
</head>
<body>
<div>
<div class="wrap">
<div class="login">
<h2>로그인 정보를 입력하세요</h2>
<div class="login_id">
<h4>Email</h4>
<input type="email" name="" id="email" placeholder="Email">
</div>
<div class="login_pw">
<h4>Password</h4>
<input type="password" name="" id="password" placeholder="Password">
</div>
<div class="submit">
<input class="mb-3" type="submit" onclick="loginCall()" value="로그인">
<p class="submit_text">아직 회원이 아니신가요?</p>
<input type="submit" onclick="location.href='/join'" value="회원가입">
</div>
</div>
</div>
</div>
</body>
</html>