티스토리 뷰
로그인, 회원가입 form의 POST
<!--login.html & signup.html-->
<form id="contactForm" method="POST">
form의 method를 POST로 바꿔주고, 회원가입창에서 sign up을 누르면 요청이 이루어진다.
# auth.py
@auth.route("/login", methods=['GET', 'POST'])
def login():
return render_template("login.html")
@auth.route("/sign-up", methods=['GET', 'POST'])
def sign_up():
return render_template("signup.html")
응답상태(200)로 만들기 위해 auth 파일의 method도 수정해준다.
request로 form에서 데이터 받아오기
<!--signup.html-->
<input class="form-control" id="email" type="text" placeholder="Enter your email..."
name="email" data-sb-validations="required"/>
input 태그에서 name 속성은 form이 제출된 후 서버에서 데이터를 참조하기 위해 사용된다.
data = request.form.get() # 플라스크의 request를 불러오는 코드
# auth.py
@auth.route("/sign-up", methods=['GET', 'POST'])
def sign_up():
if request.method == 'POST':
email = request.form.get('email')
print(email)
username = request.form.get('username')
print(username)
password1 = request.form.get('password1')
print(password1)
password2 = request.form.get('password2')
print(password2)
get()의 인자로 name의 데이터를 불러오는 코드이다.
SQLAlchemy를 이용한 데이터베이스 처리
데이터베이스를 생성하는 코드를 추가해준다.
# __init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
from flask_login import LoginManager
from pprint import pprint
# DB 설정하기
db = SQLAlchemy()
DB_NAME = "blog.db"
# def create_app():
# app = Flask(__name__)
# app.config['SECRET_KEY'] = "IFP"
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
# # blueprint 등록
# from .views import views
# app.register_blueprint(views, url_prefix="/blog")
# from .auth import auth
# app.register_blueprint(auth, url_prefix="/auth")
# DB 생성하는 함수 호출
from .models import User
create_database(app)
login_manager = LoginManager()
login_manager.login_view = "auth.login"
login_manager.init_app(app)
@login_manager.user_loader
def load_user_by_id(id):
return User.query.get(int(id))
# return app
def create_database(app):
if not path.exists("blog/" + DB_NAME):
db.create_all(app=app)
print('Created database!')
models.py
# models.py 생성
from . import db
from flask_login import UserMixin
from sqlalchemy.sql import func
class User(db.Model, UserMixin):
# id : 유일 키, Integer
id = db.Column(db.Integer, primary_key=True)
# email : 이메일 (unique), String
email = db.Column(db.String(150), unique=True)
# username : 유저이름 (unique), String
username = db.Column(db.String(150), unique=True)
# password : 비밀번호, String
password = db.Column(db.String(150))
# 생성일자, 기본적으로 현재가 저장되도록 함
created_at = db.Column(db.DateTime(timezone=True), default=func.now())
데이터베이스 모델을 정의한 파일을 생성했다. 테이블을 생성할 수 있도록 아래 코드를 __init__.py에 추가해준다.
# __init__.py
from .models import User
create_database(app)
Flask-LoginManager()
# __init__.py
from flask_login import LoginManager
flask_login 라이브러리는 플라스크에서 로그인 기능을 쉽게 구현할 수있도록 도와준다.
# models.py
from flask_login import UserMixin
UserMixin은 플라스크 로그인에서 수행하는 메소드에 대한 기본 구현을 제공한다.
# __init__.py
login_manager = LoginManager()
login_manager.login_view = "auth.login"
login_manager.init_app(app)
@login_manager.user_loader
def load_user_by_id(id):
return User.query.get(int(id))
회원가입 조건
회원가입 시 이메일이 중복되는지, 비밀번호 글자 수를 넘겼는지 확인하는 조건을 추가할 것이다.
그 전에 라이브러리를 먼저 설치한다.
pip3 install flask-wtf
pip3 install email-validator
# auth.py
import email
from unicodedata import category
from flask import Blueprint, render_template, redirect, request, flash, url_for
from flask_login import login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from blog import views
from . import db
from .models import User
# auth = Blueprint("auth", __name__)
# @auth.route("/login", methods=['GET', 'POST'])
# def login():
if request.method == 'POST':
email = request.form.get('email')
print(email)
password = request.form.get('password')
print(password)
user = User.query.filter_by(email=email).first()
if user:
if check_password_hash(user.password, password):
flash("Logged in!", category='success')
login_user(user, remember=True)
return redirect(url_for('views.home'))
else:
flash('Password is incorrect.', category='error')
else:
flash('Email does not exist.', category='error')
# return render_template("login.html")
# @auth.route("/sign-up", methods=['GET', 'POST'])
# def sign_up():
# if request.method == 'POST':
# email = request.form.get('email')
# print(email)
# username = request.form.get('username')
# print(username)
# password1 = request.form.get('password1')
# print(password1)
# password2 = request.form.get('password2')
# print(password2)
email_exists = User.query.filter_by(email=email).first()
username_exists = User.query.filter_by(username=username).first()
if email_exists:
flash('Email is already in use.', category='error')
elif username_exists:
flash('Username is already in use.', category='error')
elif password1 != password2:
flash('Password dont\'t match!', category='error')
elif len(username) < 2:
flash('Username is too short.', category='error')
elif len(password1) < 6:
flash('Password is too short.', category='error')
elif len(email) < 10:
flash('Email is invalied.', category='error')
else:
new_user = User(email=email, username=username, password=generate_password_hash(
password1, method='sha256'))
db.session.add(new_user)
db.session.commit()
login_user(new_user, remember=True)
flash('User_created!')
return redirect(url_for('views.home'))
# return render_template("signup.html")
@auth.route("/logout")
@login_required
def logout():
logout_user()
return redirect("views.home")
비밀번호 해싱
# auth.py
from werkzeug.security import generate_password_hash, check_password_hash
new_user = User(email=email, username=username, password=generate_password_hash(
password1, method='sha256'))
auth.py 에 위의 코드를 추가해주면 회원정보가 SQL에 추가되는데 비밀번호는 암호화되어있는 것을 볼 수 있다.
로그인 처리하기
# auth.py
@auth.route("/login", methods=['GET', 'POST'])
def login():
if request.method == 'POST':
email = request.form.get('email')
print(email)
password = request.form.get('password')
print(password)
user = User.query.filter_by(email=email).first()
if user:
if check_password_hash(user.password, password):
flash("Logged in!", category='success')
login_user(user, remember=True)
return redirect(url_for('views.home'))
else:
flash('Password is incorrect.', category='error')
else:
flash('Email does not exist.', category='error')
return render_template("login.html")
회원가입, 로그인이 성공하면 blog home 화면으로 이동한다.
로그아웃 처리하기
# auth.py
@auth.route("/logout")
@login_required
def logout():
logout_user()
return redirect("views.home")
로그인이 되어있어야 로그아웃을 할 수 있으므로, 로그인이 됐는지 확인해주는 @login_required를 추가해준다.
그 후 logout_user( )를 추가하여 로그아웃을 완료한다.
오류메시지 나타내기
<!--base.html-->
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
{% for category, message in messages %}
{{ message }}
{% endfor %}
{% endif %}
{% endwith %}
위의 코드로 작동되는지 확인했다면 디자인 요소를 추가한 아래 코드로 바꿔준다.
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
{% for category, message in messages %}
{# 카테고리 == error 이라면, 실패 메시지를 출력 #}
{% if category == "error" %}
<div class="alert alert-danger alert-dismissable fade show" role="alert" style="text-align: center">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{# 그렇지 않다면, 성공 메시지를 출력 #}
{% else %}
<div class="alert alert-success alert-dismissable fade show" role="alert" style="text-align: center">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endwith %}
로그인 시 변화하는 동적 nav
<!--base.html-->
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ms-auto py-4 py-lg-0">
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{{url_for('views.home')}}">Home</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{{url_for('views.about')}}">About</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{{url_for('views.categories_list')}}">Categories</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{{url_for('views.contact')}}">Contact</a></li>
{% if user.is_authenticated %}
{# 유저가 로그인했다면 보일 것들 : "Welcome, username", "Logout" 이고, user 정보가 넘어가야 함. #}
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" style="color: red"
href="#">welcome, {{ user.username }}!</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" style="color: red"
href="{{ url_for('auth.logout') }}">Logout</a></li>
{% endif %}
{% if not user.is_authenticated %} {# 그리고, 로그인한 상태가 아니라면... #}
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4"
href="{{ url_for('auth.signup') }}">Sign Up</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4"
href="{{ url_for('auth.login') }}">Login</a></li>
{% endif %}
</ul>
</div>
# auth.py
return render_template("login.html", user=current_user)
return render_template("signup.html", user=current_user)
# views.py
# base.html이 들어가는 모든 html에 user=current_user 추가
참고
'Python > 파이썬 플라스크' 카테고리의 다른 글
[5주차-2] 카테고리, 게시물 구현 (수정) (0) | 2022.08.07 |
---|---|
[5주차] 관리자 페이지 (0) | 2022.08.07 |
[3주차-2] render_template (0) | 2022.07.11 |
[3주차] __init__ / blueprint (0) | 2022.07.11 |
[2주차-2] Python DB API/SQLite3 (0) | 2022.07.08 |
댓글