정화 코딩

이화마켓 웹어플리케이션 개발 : 로그인/회원가입 화면 구현하기 본문

Web Development

이화마켓 웹어플리케이션 개발 : 로그인/회원가입 화면 구현하기

jungh150c 2023. 12. 4. 11:41

현재 이화마켓 웹어플리케이션을 개발하는 과정 중에 있는데, 그 중 로그인/회원가입 화면은 어느 서비스에서든 활용할 수 있는 필수적인 화면이라고 생각한다. 따라서 웹어플리케이션 개발을 하고자 하는 다른 사람들에게 도움이 되었으면 좋겠다고 생각하여 우리가 이 화면을 어떻게 구현하였는지에 대해 적어보고자 한다. 

 


회원가입 화면

 

💡 기능

 

- 회원가입 버튼이 클릭되면 사용자가 입력한 아이디, 비밀번호, 닉네임을 받아 백엔드로 넘긴다.

- 아이디가 중복되지 않는지 체크한다. 중복된 아이디라면 이를 알려주는 메세지 창을 보여주고 회원가입 화면으로 이동한다. 중복되지 않은 아이디라면 정상적으로 데이터베이스에 사용자 정보를 추가하고 로그인 화면으로 이동한다. (비밀번호는 암호화하여 저장한다.)

 

💡 구현

 

- app.py 일부

@application.route("/signup")
def signup():
    return render_template("signup.html")

네비게이션 바에서 회원가입 버튼을 클릭하면 회원가입 화면으로 이동한다.

 

- signup.html

{% extends "index.html" %}

{% block section %}
{% with mesg = get_flashed_messages() %}
{% if mesg !=[] %}
<script>alert("{{ mesg[0] }}")</script>
{% endif %}
{% endwith %}
<style>
  .wrapper {
    width: 700px;
    height: 350px;
    padding: 40px;
    margin: auto;
    box-sizing: border-box;
  }

  #title {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  #signup-form>input {
    width: 100%;
    height: 40px;
    box-sizing: border-box;
    margin-bottom: 16px;
    border-radius: 6px;
    border: 1px solid #c4c4c4;
    background-color: #F8F8F8;
  }

  #signup-form>input[type="submit"] {
    color: rgb(36, 81, 100);
    font-size: 16px;
    background-color: rgb(163, 223, 249, 0.75);
    margin-top: 20px;
  }
</style>
<div class="wrapper">
  <br>
  <h2 id="title">회원가입</h2>
  <hr><br>
  <form method="post" action="/signup_post" id="signup-form" style="width: 70%; margin: auto;">
    <p>ID : </p>
    <input type="text" name="id" required>
    <p>password : </p>
    <input type="password" name="pw" required>
    <p>Nickname : </p>
    <input type="text" name="nickname"><br><br>
    <input type="submit" value="회원가입" id="signupBtn" /></p>
  </form>
</div>
{% endblock section %}

회원가입 화면의 html 파일이다. index.html로부터 확장되어 위에 네비게이션 바가 보이고, style은 html 파일 내부에 정의하였다. 사용자가 입력한 정보들은 form에 담겨 post 방식으로 전달되고 "/signup_post"가 이 정보들을 처리하도록 한다. 

 

- app.py 일부

@application.route("/signup_post", methods=['POST'])
def register_user():
    data = request.form
    pw = request.form['pw']
    pw_hash = hashlib.sha256(pw.encode('utf-8')).hexdigest()
    if DB.insert_user(data, pw_hash):
        return render_template("login.html")
    else:
        flash("user id already exist!")
        return render_template("signup.html")

정보를 전달받은 "/signup_post"는 비밀번호를 암호화한 뒤, DB 함수 insert_user를 통해 데이터베이스에 사용자 정보를 추가한다.

 

- database.py 일부

# 회원가입
def insert_user(self, data, pw):
    user_info = {
        "pw": pw,
        "nickname": data['nickname']
    }
    if self.user_duplicate_check(str(data['id'])):
        self.db.child("users").child(data['id']).child(
            "user_info").set(user_info)
        return True
    else:
        return False
        
# 회원가입 시 중복 체크
def user_duplicate_check(self, id_string):
    users = self.db.child("users").get()
    if str(users.val()) == "None":  # 첫 회원가입
        return True
    else:
        if id_string in users.val():
            return False
    return True

중복된 아이디가 없을 때만 정상적으로 데이터베이스에 사용자 정보가 추가되고, 그렇지 않을 때는 False가 반환되게 한다. 단, 사용자 정보가 비어 있을 때, 즉 첫 회원가입의 경우에는 아이디 중복을 체크하지 않고 무조건 추가되도록 한다. 

 

- 화면

 


로그인 화면

 

💡 기능

 

- 로그인 버튼이 클릭되면 사용자가 입력한 아이디, 비밀번호를 받아 백엔드로 넘긴다.

- 데이터베이스에 저장된 사용자 정보들을 하나씩 체크하며 일치하는 아이디가 있는지 체크하고, 있다면 비밀번호가 일치하는지 확인한다. 

- 일치하는 아이디가 없거나 비밀번호가 틀렸으면 이를 알려주는 메세지 창을 보여주고 로그인 화면으로 이동한다. 아이디롸 비밀번호가 모두 일치해 로그인에 성공하였다면 session에 사용자의 아이디 값을 저장하고 홈화면으로 이동한다. 

- 로그인 버튼과 회원가입 버튼은 마이 페이지 버튼과 로그아웃 버튼으로 바뀐다.

- 모든 페이지에서 session에 접근할 수 있어, 현재 로그인된 사용자의 정보를 찾을 수 있다. 

 

💡 구현

 

- app.py 일부

@application.route("/login")
def login():
    return render_template("login.html")

네비게이션 바에서 로그인 버튼을 클릭하면 로그인 화면으로 이동한다.

 

- login.html

{% extends "index.html" %}

{% block section %}
{% with mesg = get_flashed_messages() %}
{% if mesg !=[] %}
  <script>alert("{{ mesg[0] }}")</script>
{% endif %}
{% endwith %}
<style>
  .wrapper {
    width: 700px;
    height: 350px;
    padding: 40px;
    margin: auto;
    box-sizing: border-box;
  }

  #title {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  #login-form>input {
    width: 100%;
    height: 40px;
    box-sizing: border-box;
    margin-bottom: 16px;
    border-radius: 6px;
    border: 1px solid #c4c4c4;
    background-color: #F8F8F8;
  }

  #login-form>input[type="submit"] {
    color: rgb(36, 81, 100);
    font-size: 16px;
    background-color: rgb(163, 223, 249, 0.75);
    margin-top: 20px;
  }

  #signup-btn {
    width: 100%;
    height: 40px;
    box-sizing: border-box;
    margin-bottom: 16px;
    border-radius: 6px;
    border: 1px solid #c4c4c4;
    background-color: #F8F8F8;
    font-size: 16px;
    margin-top: 20px;
  }
</style>
<div class="wrapper">
  <br>
  <h2 id="title">로그인</h2>
  <hr><br>
  <form action="/login_confirm" method="post" id="login-form" style="width: 70%; margin: auto;">
    <p>ID : </p>
    <input type="text" name="id">
    <p>password : </p>
    <input type="password" name="pw"><br><br>
    <input type="submit" value="로그인" id="loginBtn" /><br>
  </form>
  <!-- <p>아직 회원이 아니신가요?</p> -->
  <div style="width: 70%; margin: auto;">
    <a href="/signup"><button onclick="/signup" id="signup-btn">회원가입</button></a>
  </div>
</div>
{% endblock section %}

 

로그인 화면의 html 파일이다. index.html로부터 확장되어 위에 네비게이션 바가 보이고, style은 html 파일 내부에 정의하였다. 사용자가 입력한 정보들은 form에 담겨 post 방식으로 전달되고 "/login_cnofirm"가 이 정보들을 처리하도록 한다. 

 

- app.py 일부

@application.route("/login_confirm", methods=['POST'])
def login_user():
    id = request.form['id']
    pw = request.form['pw']
    pw_hash = hashlib.sha256(pw.encode('utf-8')).hexdigest()
    if DB.find_user(id, pw_hash):
        session['id'] = id
        return redirect(url_for('hello'))
    else:
        flash("Wrong ID or PW!")
        return render_template("login.html")

정보를 전달받은 "/login_cnofirm "는 비밀번호를 암호화한 뒤, DB 함수 find_user를 통해 해당하는 아이디와 비밀번호를 가진 사용자가 있는지 확인한다. 정상적으로 로그인이 되면 session에 아이디 값을 저장한다. session은 모든 화면에서 접근할 수 있는 데이터이다. 

 

- database.py 일부

def find_user(self, id, pw):
        users = self.db.child("users").get()
        for user in users.each():
            user_id = user.key()
            if user_id == id:
                user_data = user.val()
                user_info = user_data.get("user_info")
                if user_info.get("pw") == pw:
                    return True
                else:
                    return False
        return False 

해당하는 아이디가 존재하고 비밀번호까지 일치하면 정상적으로 로그인되고, 그렇지 않을 때는 False가 반환되게 한다. 

 

- index.html 일부

<body>
  <nav class="navbar">
    <div class="navbar__logo">
      <a href="/"><img src="/static/images/logo.png" id="navbar-logo" alt="이화마켓" height="40px"></a>
    </div>
    <ul class="navbar__menu">
      <li><a href="/reg_item">Register Items</a></li>
      <li><a href="/user_reviews/{{session['id']}}/">My Reviews</a></li> <!--일단 누르면 현재 세션의 아이디로 들어가게 함-->
    </ul>
    <ul class="navbar__login">
      <li><a href="/product_list">모두의 마켓</a></li>
      {% if session['id'] %}
      <li><a href="/my_page/{{session['id']}}/" id="nav-mypage">{{session['id']}}님의 마이 페이지</a></li>
      <li><a href="/logout" id="nav-logout">로그아웃</a></li>
      {% else %}
      <li><a href="/login" id="nav-login">로그인</a></li>
      <li><a href="/signup" id="nav-signup">회원가입</a></li>
      {% endif %}
    </ul>
  </nav>
  <div id="navbar-gra"></div>
  <section>
    {% block section %}

    {% endblock section %}
  </section>
</body>

session에 아이디 값이 있으면, 즉 로그인 되어있는 상태이면 네비게이션 바 우측에 마이 페이지와 로그아웃 버튼이 보이도록 하고, 로그인 되어있지 않은 상태이면 로그인과 회원가입 버튼이 보이도록 한다. 

 

- 화면

 


로그아웃

 

💡 기능

 

- 로그아웃 버튼이 클릭되면 session을 초기화한다. 

 

💡 구현

 

- app.py 일부

@application.route("/logout")
def logout_user():
    session.clear()
    return redirect(url_for('hello'))

 

Comments