본문 바로가기

Projects/Flask + MongoDB K리그 일정서비스

#2. 회원가입 및 로그인

로그인 기능과 회원가입 기능에 대해서 정리하고자 한다. 이 두가지 기능을 위해서는 어떻게 api를 설계해야 할까.

 

우선, 로그인 기능에 대해,

1) 로그인페이지가 있어야 한다.

2) 로그인페이지에서 아이디와 패스워드를 입력 후 로그인 요청을 누르면 api로 post요청이 간다. 이 때, api에서 렌더링할 필요 없이, 프론트 단에서 post요청을 처리하기 위해, ajax통신이나 혹은 fetch를 사용할 수 있다.

3) api단에서는, post요청에 담긴 id와 패스워드를 DB에서 찾는다.

4) DB에서 찾았다면, 유저정보에 따른 토큰을 발급해준다.

5) 최종적으로 로그인한 유저정보, 그리고 유저정보에 따른 토큰을 같이 보내준다.

6) api에서는 렌더링해줄 필요가 없기 때문에, ajax나 fetch에서는 json으로 응답을 받게 되고, 이후에 이걸 ui상에서 렌더링해주면 된다.

 

소스코드를 살펴보자.

# 로그인 요청
@app.route('/api/sign_in', methods=['POST'])
def sign_in():
    
    //POST요청에 담긴 id와 pw를 꺼낸다
    userId = request.form['userId']
    userPw = request.form['userPw']
	
    //POST요청에 담겼던 PW를 암호화시킨다
    //회원가입 시 PW를 암호화해서 저장했기 때문이다
    pw_hash = hashlib.sha256(userPw.encode('utf-8')).hexdigest()
    
    //암호화된 PW같과 같은 PW 및 ID를 DB에서 찾는다. users라는 collection에 들어있다.
    result = db.users.find_one({'user_id': userId, 'user_pw': pw_hash})
	
    //찾았다면, 즉 db에 로그인요청한 id와 pw가 존재한다면,
    if result is not None:
        
        //토큰 발급을 위해 id와 현재시각을 payload에 담고,
        payload = {
            'id': userId,
            'exp': datetime.utcnow() + timedelta(seconds=60 * 60 * 24)  # 로그인 24시간 유지
        }
        
        //이 payload를 기반으로 토큰을 발급한다
        token = jwt.encode(payload, SECRET_KEY, algorithm='HS256').decode('utf-8')
		
        //로그인요청이 성공했다는 메시지와 함께, 토큰을 응답해준다
        return jsonify({'result': 'success', 'token': token})
    else:
        return jsonify({'result': 'fail', 'msg': '아이디/비밀번호가 일치하지 않습니다.'})

 

이렇게 로그인 기능을 위해선, 회원가입 기능이 우선되어야 한다. 일단은 DB에 유저정보가 있어야 하기 때문이다. 

 

# 회원가입 요청
@app.route('/sign_up/save', methods=['POST'])
def sign_up():
	
    //post요청에 담긴 유저정보를 꺼낸다
    user_id = request.form['userId']
    user_pw = request.form['userPw']
    nick_name = request.form['nickName']
    
    //관리자 계정이 아닌 일반 회원등급 설정
    grade = 0
    
    //패스워드를 저장할 때, 보안을 위해 암호화해서 저장한다
    password_hash = hashlib.sha256(user_pw.encode('utf-8')).hexdigest()
    
    //회원가입 시간설정
    now = datetime.now()
    nowDatetime = now.strftime('%Y-%m-%d %H:%M:%S')
    
    //회원가입 정보를 객체에 담고,
    doc = {
        "user_id": user_id,
        "user_pw": password_hash,
        "nick_name": nick_name,
        "grade": int(grade),
        "join_date": nowDatetime
    }
    
    //이를 users라는 collection에 저장
    db.users.insert_one(doc)
    
    //저장이 성공적으로 되었다고 응답해줌
    return jsonify({'result': 'success'})


# 회원가입 페이지
@app.route('/signUp')
def sign_up_page():
    return render_template('signUp.html')
    
# 아이디 중복체크
@app.route('/sign_up/check_dup', methods=['POST'])
def check_dup():
    
    //post요청에 담긴 가입희망 id를 꺼내서
    userId = request.form['userId']
    
    //이게 db에 있는지 확인한다. 결과값으로 true or false를 반환
    exists = bool(db.users.find_one({"user_id": userId}))
    return jsonify({'result': 'success', 'exists': exists})