티스토리 뷰

로그인, 회원가입 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 추가

참고

https://youtu.be/W4GItcW7W-U
https://gdsanadev.com/14464

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday