본문 바로가기
Programming/Python_Web

Flask강좌6 - 등록/로그인/로그아웃

by Wilkyway 2020. 12. 4.
반응형

지금까지 DB 검색 기능에 대해 만들었으나, 사용자 등록, 로그인, 로그아웃 처리를 위해 대대적인 수정이 있겠습니다.

 

 

1. users 테이블 구성

우선 시작은 Database 구성부터 하도록 하겠습니다. 지난 members 테이블과는 별도로 사용자 관리를 위한 users 테이블을 생성하도록 하겠습니다.

 

2.user_model.py

데이터베이스 테이블에 맞춰 User클래스를 생성합니다. 정보는 ID, 이름, 비번이 되겠습니다.

from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

db = SQLAlchemy()

class User(db.Model):
    __tablename__ = 'users'   #테이블 이름 : users

    id = db.Column(db.Integer, primary_key = True)   #id를 프라이머리키로 설정
    userid = db.Column(db.String(32))
    username = db.Column(db.String(8))
    password = db.Column(db.String(64))

3.register.html

다음으로 사용자 등록화면인 register.html을 구성하겠습니다. 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Register Form</title>
</head>
<body>
<div>
    <h1>회원가입</h1>
</div>
<div>
    <form method="POST" action="/register">
        <div>
            <label for="userid">아이디</label>
            <input type="text" id="userid" placeholder="아이디" name="userid"/>
        </div>
        <div>
            <label for="username">이름</label>
            <input type="text" id="username" placeholder="이름" name="username"/>
        </div>
        <div>
            <label for="password">비밀번호</label>
            <input type="password" id="password" placeholder="비밀번호" name="password"/>
        </div>
        <div>
            <label for="re_password">비밀번호 확인</label>
            <input type="password" id="re_password" placeholder="비밀번호 확인" name="re_password"/>
        </div>
        <button type="submit">등록</button>
    </form>
</div>

</body>
</html>

화면 구성에 대해서는 최대한 자제하고 로직 구성에만 전념하겠습니다. 이에 대한 라우팅은 아래와 같이 구성합니다.

@app.route('/register', methods=['GET','POST'])
def register():
	if request.method =='GET':
		return render_template("register.html")
	else:
		userid = request.form.get('userid')
		username = request.form.get('username')
		password = request.form.get('password')
		re_password = request.form.get('re_password')

		if not (userid and username and password and re_password):
			return "모두 입력해주세요"
		elif password != re_password:
			return "비밀번호를 확인해주세요"
		else:
			user = User()
			user.password = password
			user.userid = userid
			user.username = username
			db.session.add(user)
			db.session.commit()
			return "회원가입 완료"
		return redirect('/')

최초 /register에 접속할 때에는 GET 방식으로 단순 html 파일을 보여주고, html 내 form 양식에 의해

<form method="POST" action="/register"> 로 불러질 때에는 POST 방식에 의해 수행이 됩니다. POST 방식에서는 아이디, 이름, 비번, 비번확인을 받아들여서, 하나라도 빠진게 있으면 체크하고, 비번과 비번확인이 다르면 체크하며, 모두 통과하면 users 테이블에 입력합니다. 입력이 완료되면 '/'으로 리다이렉트 됩니다.

 

4.login.html

로그인 페이지를 아래와 같이 구성합니다. 조금 뒤에 나오겠지만, 'userid'라는 session정보가 있을 경우 이미 로그인 했음을 알려주고, 그렇지 않을 경우 로그인 폼을 보여줍니다. 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
{% if session['userid'] %}
    <p>이미 로그인 하셨습니다.</p>
{% else %}
<center>
    <div>
        <h2>Login</h2>
        <form action="/login" method="POST">
            <input type="userid" name="userid" placeholder="Userid">
            <input type="password" name="password" placeholder="Password">
            <br><br>
            <input type="submit" value="로그인">
        </form>
    </div>
</center>
{% endif %}
</body>
</html>

# login 페이지 접속(GET) 처리와, "action=/login" 처리(POST)처리 모두 정의
@app.route('/login', methods=['GET', 'POST'])	
def login():
	if request.method=='GET':
		return render_template('login.html')
	else:
		userid = request.form['userid']
		password = request.form['password']
		try:
			data = User.query.filter_by(userid=userid, password=password).first()	# ID/PW 조회Query 실행
			if data is not None:	# 쿼리 데이터가 존재하면
				session['userid'] = userid	# userid를 session에 저장한다.
				return redirect('/')
			else:
				return 'Dont Login'	# 쿼리 데이터가 없으면 출력
		except:
			return "dont login"	# 예외 상황 발생 시 출력

@app.route('/logout', methods=['GET'])
def logout():
	session.pop('userid', None)
	return redirect('/')

로그인 폼을 보여줄 'GET' 방식과, 로그인 처리(사용자 확인)를 위한 'POST'방식을 모두 정의합니다. GET이면 login.html을 곧바로 보여주고, POST방식일 경우 login.html 내 폼에서 userid와 password 부분을 가져와서 database 조회를 합니다. 조회가 성공하면 session['userid']에 폼으로부터 전달받은 userid값을 저장하고 '/'으로 이동합니다. 데이터가 없거나, 예외가 발생하면 그에 따른 처리를 각각 해 줍니다.

 

아울러 '/logout'에 대해서도 함께 정의해줍니다. 이 때에는 GET만 정의하면 됩니다. 

 

5. __init__.py 수정

순서가 뒤죽박죽이 된 것 같네요. 위에서 세션을 사용한 코드를 이미 작성했는데.....한가지, Flask에서는 세션을 사용하려면 어플리케이션에 정의된 시크릿키(SECRET_KEY)가 필요합니다. 이 키로 서명된 쿠키가 사용된다고 합니다. 꼭 잊지말고 넣어주도록 합시다.

그밖에 기존에 사용자 인증과 관련없는 라우팅은 지면관계상 지우도록 하겠습니다.

@app.route('/home')도 지워버리고, 대신 home.html을 '/' 에서 라우팅하도록 하였습니다. 단 session['userid']가 있을 경우와 없을 경우를 나누어 처리하도록 하였습니다. 

from flask import Flask, render_template, request, redirect, session, url_for
from flask_sqlalchemy import SQLAlchemy
from helloflask.model.user_model import Member, User


app = Flask(__name__)

app.secret_key="123123123"

# database 설정파일
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:1234@localhost:3306/testdb"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)

@app.route('/')
def home():
	#로그인 세션정보('userid')가 있을 경우
	if not session.get('userid'):  
		return render_template('home.html')
	
	#로그인 세션정보가 없을 경우
	else:		
		userid = session.get('userid') 
		return render_template('home.html', userid=userid)

# @app.route('/home') 삭제
# @app.route('/one') 삭제
# @app.route('/all') 삭제
# @app.route('/search', methods=['POST','GET']) 삭제

# register 페이지 접속(GET) 처리와, "action=/register" 처리(POST) 모두 정의
@app.route('/register', methods=['GET','POST'])
def register():
	if request.method =='GET':
		return render_template("register.html")
	else:
		userid = request.form.get('userid')
		username = request.form.get('username')
		password = request.form.get('password')
		re_password = request.form.get('re_password')

		if not (userid and username and password and re_password):
			return "모두 입력해주세요"
		elif password != re_password:
			return "비밀번호를 확인해주세요"
		else:
			user = User()
			user.password = password
			user.userid = userid
			user.username = username
			db.session.add(user)
			db.session.commit()
			return "회원가입 완료"
		return redirect('/')

# login 페이지 접속(GET)처리와, "action=/login" 처리(POST)모두 정의
@app.route('/login', methods=['GET', 'POST'])	
def login():
	if request.method=='GET':
		return render_template('login.html')
	else:
		userid = request.form['userid']
		password = request.form['password']
		try:
			data = User.query.filter_by(userid=userid, password=password).first()	# ID/PW 조회Query 실행
			if data is not None:	# 쿼리 데이터가 존재하면
				session['userid'] = userid	# userid를 session에 저장한다.
				return redirect('/')
			else:
				return 'Dont Login'	# 쿼리 데이터가 없으면 출력
		except:
			return "dont login"	# 예외 상황 발생 시 출력

@app.route('/logout', methods=['GET'])
def logout():
	session.pop('userid', None)
	return redirect('/')

 

6. home.html 수정

userid 세션이 존재할 경우 logout 버튼이 나오도록 처리하고, userid 세션이 없을 경우에는 등록하기와 로그인 버튼이 나타나도록 처리했습니다.

{% extends "layout.html" %}
{% block content %}

<div class="jumbo">
    <h2>Hello Flask App</h2>
    {% if session['userid'] %}
        <h4>{{ userid }}님 요청 처리에 대한 페이지입니다.</h4>
        <button type="button" onclick="location.href='/logout' ">로그 아웃</button>
    {% else %}
        <h4>Hello World!</h4>
        <button type="button" onclick="location.href='/register' ">등록하기</button>
        <button type="button" onclick="location.href='/login' ">로그인</button>
    {% endif %}
</div>
{% endblock %}

<로그인 세션이 없을 경우>

<로그인 세션이 존재할 경우>

 

~~끝~~

반응형

'Programming > Python_Web' 카테고리의 다른 글

FastAPI 시작하기  (0) 2021.09.09
FastAPI - Jinja2로 프론트 적용하기  (0) 2021.09.09
Flask강좌5 - Flask form입력  (0) 2020.12.03
Flask강좌4 - Flask_SQLAlchemy MySQL연동  (5) 2020.12.02
Flask강좌3 - Request  (0) 2020.12.01

댓글