[0517] TIL 24일차

nikevapormax·2022년 5월 17일
0

TIL

목록 보기
23/116
post-custom-banner

😂 거북이반 인스타 클론코딩

  • 인스타그램 클론코딩을 진행하며 구현력이 좋지 않은 것도 사실이지만, 내가 작성했던 코드말고 다른 종류의(?) 코드로도 구현을 해보고 싶었다. 실제로 이번 거북이반 인스타 클론코딩을 튜터님의 지휘 아래에서 다시 진행하면서 많은 점이 달라졌다.
    • 여태까지의 개인 및 팀 프로젝트로 구현한 클론코딩은 프론트와 백앤드가 하나의 파일 안에 같이 있었다. 이번 거북이반 인스타 클론코딩에서는 프론트와 백앤드가 아예 다른 파일로 분리되어 진행되었다.
    • 데이터를 받아오는 방식 자체도 이전과 다르다. 이전에는 request.form 형식을 사용해 데이터를 받아왔다면, 이번에는 데이터를 아예 JSON 형식으로 받아와 진행하고 있다.
      	data = json.loads(request.data)
          email_receive = data.get('email')

😭 회원가입 기능 구현

  • 이메일
    • 이메일을 검증하는 부분에 정규식을 사용해야 하나 아직 하지 못했다.
    • 이메일이 비어있거나 이메일 형식이 아닌 다른 형식의 문자열이 쓰인 경우에는 회원가입을 하지 못하도록 막았다.
  • 비밀번호
    • 이메일과 마찬가지로 빈 값을 넣으면 회원가입을 하지 못하도록 막았다.
    • 해쉬 알고리즘으로 비밀번호를 암호화하여 db에 넘기도록 하였다.
  • jasonify 부분의 201은 임시 방편으로 작성하였다. 회원가입 버튼만 누르거나 빈 값이어도 프론트 부분에서는 회원가입이 된 것으로 인정되어 status code가 어떤 경우에도 200으로 나와 201로 성공한 경우를 한정하였다.
@app.route("/signup", methods=['POST'])
def sign_up():
    # JSON 형식으로 데이터 받음
    data = json.loads(request.data)

    email_receive = data.get('email')
    domain = ['naver.com', 'gmail.com', 'daum.net']
    if '@' in email_receive:
        if email_receive.split('@')[1] in domain:
            if db.user.find_one({'email': email_receive}):
                return jsonify({'msg': '이미 존재하는 이메일입니다.'})
            else:
                email = email_receive
        else:
            return jsonify({'msg': '도메인을 확인해주세요.'})
    elif email_receive == '':
        return jsonify({'msg': '이메일 칸이 비었습니다.'})
    else:
        return jsonify({'msg': '이메일 형식으로 입력바랍니다.'})

    password_receive = data.get('password')
    if password_receive == '':
        return jsonify({'msg': '비밀번호를 입력해주시기 바랍니다.'})
    else:
        password_hash = hashlib.sha256(
            password_receive.encode('utf-8')).hexdigest()

    doc = {
        'email': email,
        'password': password_hash
    }
    db.user.insert_one(doc)

    return jsonify({'msg': 'Signup success! Welcome!'}), 201
  • javascript의 비동기 처리를 다룰 수 있는 방법 중 하나인 async/await를 사용하였다.
const backend_base_url = 'http://127.0.0.1:5000'
const frontend_base_url = 'http://127.0.0.1:5500/frontend'

async function handleSignup() { // async를 붙여주어 '비동기함수'임을 알려줌

    // email과 password의 값을 가져옴
    const signupData = {
        email: document.getElementById('floatingInput').value,
        password: document.getElementById('floatingPassword').value
    }
    // await을 붙여주어 해당 부분이 '비동기' 부분임을 알려줌
    const response = await fetch(`${backend_base_url}/signup`, {
        method: "POST",
        body: JSON.stringify(signupData)
    })

    console.log(response)

    if (response.status == 201) { // 회원가입에 성공하게 되면 로그인 페이지로 넘어가게 됨
        alert('회원가입에 성공하였습니다!');
        window.location.replace(`${frontend_base_url}/login.html`);
    } else { // 회원가입에 실패하게 되면 경고문 
        alert('회원가입에 실패하였습니다. 다시 시도해주세요!');
        window.location.reload();
    }
}

😭 로그인 기능 구현

  • 사용자가 로그인에 필요한 값을 입력하고 백앤드로 정보를 보낼 때 사용자의 정보가 누출되지 않도록하기 위해 POST 형식을 사용하였다.
  • 사용자의 이메일과 비밀번호를 받은 후, 해당 정보가 user db에 있는지 확인 하는 과정을 통해 회원가입 유무 확인이 가능하다.
  • ObjectId를 받아와 id로 사용하였다. 진짜 지금까지 저 값을 찾을라고 별 짓을 다했는데, 이렇게 쉽게 받아오니까 현타가 쎄게 왔었다.
  • 토큰 발급을 위해 사용자의 중요한 정보를 제외한 값들을 payload에 넣어주고, 이를 암호화하였다.
  • 토큰값을 가져야 할 사용자의 db에 넣어주기 위해 update를 사용하였다.
  • 여기서도 로그인에 성공한다면 status.code의 값을 201로 주어 프론트에서의 문제를 해결하였다. 추후 수정할 사항 중 하나이다.
@app.route("/signin", methods=['POST'])
def sign_in():
    data = json.loads(request.data)
    my_email = data.get('email')
    password_receive = data.get('password')
    my_pw = hashlib.sha256(password_receive.encode('utf-8')).hexdigest()

    my_signin = db.user.find_one({'email': my_email, 'password': my_pw})
    print(my_signin)

    if my_signin is not None:
        payload = {
            'id': str(my_signin['_id']),
            'email': my_email,
            'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=60 * 60 * 24)
        }
        print(payload)
        token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
        # 발급받은 token을 user db의 해당 유저에게 할당
        db.user.update_one({'email': my_email}, {'$set': {'token': token}})
        return jsonify({'msg': 'Login success! Welcome!', 'token': token}), 201
    else:
        return jsonify({'result': 'fail', 'msg': '아이디/비밀번호가 일치하지 않습니다.'})
  • 저번 프로젝트보다 난이도를 쉽게 가져가기 위해 토큰의 값을 로컬 스토리지에 저장하는 방법을 채택하였다.
    • setItem과 getItem을 통해 각각 로컬 스토리지에 저장할 값을 넣고 뺄 수 있다.
async function handleSignin() { // async를 붙여주어 '비동기함수'임을 알려줌

    // email과 password의 값을 가져옴
    const signinData = {
        email: document.getElementById('floatingInput').value,
        password: document.getElementById('floatingPassword').value
    }
    // await을 붙여주어 해당 부분이 '비동기' 부분임을 알려줌
    const response = await fetch(`${backend_base_url}/signin`, {
        method: "POST",
        body: JSON.stringify(signinData)
    })

    console.log(response)
    response_json = await response.json()
    console.log(response_json)
    localStorage.setItem("token", response_json.token)

    if (response.status == 201) {
        alert('로그인에 성공하였습니다!');
        window.location.replace(`${frontend_base_url}/index.html`);
    } else {
        alert('로그인에 실패했습니다. 재시도해주세요!');
        window.location.reload();
    }
}

😭 로그인 기능 구현

  • 프론트 단에서 headers에 넣어 보내준 Authorization 값에서 토큰값을 받아온 후, 토큰값이 있다면 해당 값을 복호화하여 원하는 값을 사용하고 있다.
  • 로그인 기능에서 payload에 같이 넣어준 _id 값을 사용해 사용자의 정보를 가져온 뒤, 우리가 아이디로 사용하고 있는 email 값을 리턴값으로 돌려주고 있다.
@app.route("/getuserinfo", methods=['GET'])
def get_user_info():
    token = request.headers.get('Authorization')
    if not token:
        return jsonify({'msg': 'check your token again...'})
    print('1', token)
    user_payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
    print('2', user_payload)
    user_info = db.user.find_one({'_id': ObjectId(user_payload['id'])})
    print('3', user_info)

    return jsonify({'msg': 'success', 'email': user_info['email']})
  • 해당 함수를 사용하는 데 에러가 나 완벽하게 구현하지 못했다.
  • getName 함수를 사용해 메인 페이지에 백앤드에서 리턴해준 사용자의 이메일을 화면에 띄워주려 했으나 아래와 같은 에러가 나 해결하지 못하고 있다.
async function getName() {
    const response = await fetch(`${backend_base_url}/getuserinfo`, {
        headers: {
            'Authorization': localStorage.getItem('token')
        }
    })
    console.log(response)

    response_json = await response.json()
    console.log(response_json)

    const usermail = document.getElementById('usermail')
    usermail.innerText = response_json.email

    return response_json.email
}
profile
https://github.com/nikevapormax
post-custom-banner

0개의 댓글