본문 바로가기

TIL/Python

[Flask] 여러 사용자의 가입과 로그인을 관리해보자

0. 사용자.db을 만든다.

사용자로 부터 입력받은 데이터를 이용해 사용자db을 만든다.

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(1000))

이메일 비밀번호 이름을 정보를 받는다.

UserMixin 은 flask_login에서 가져온 함수 이다.

@app.route('/register', methods=["GET", "POST"])
def register():
    if request.method == "POST":

        new_user = User(
            email=request.form.get('email'),
            name=request.form.get('name'),
            password=request.form.get('password')
        )

        db.session.add(new_user)
        db.session.commit()

        return redirect(url_for("secrets"))

    return render_template("register.html")

이때 보안을 위해서 사용자 암호를 그대로 데이터베이스에 저장하는 것은 추천하지 않는다.

플라스크 다운받을 때 저장되어 있던 werkzeug을 이용해서 비밀번호를 암호화 하자


1. 비밀번호 암호화 해서 저장하기

werkzeug에 있는 함수 중 .generate_password_hash() 을 이용하자

이런 걸 salt 라고 하는 데 소금치는 것 처럼 기존의 비밀번호를 조금 다르게 저장하는 것이다.

werkzeug.security.generate_password_hash(password, method='pbkdf2:sha256', salt_length=8)
@app.route('/register', methods=["GET", "POST"])
def register():
    if request.method == "POST":

        hash_and_salted_password = generate_password_hash(
            request.form.get('password'),
            method='pbkdf2:sha256',
            salt_length=8
        )
        new_user = User(
            email=request.form.get('email'),
            name=request.form.get('name'),
            password=hash_and_salted_password
        )

        db.session.add(new_user)
        db.session.commit()

        return redirect(url_for("secrets"))

    return render_template("register.html")

다시 User.db에 새로 저장하기 위해

새로운 변수

hash_and_salted_password = generate_password_hash( 바꿀정보, 방법=,추가할길이=) 로 할당해서

데이터 베이스에 저장한다.

데이터베이스에 저장했다고해서 그걸로 끝이 아니다.

이 데이터를 근거 기존에 사용했던 이메일이라던가 비밀번호가 틀렸다는 걸 확인하고 접근할수 있도록 도와주는

flask_login을 사용하자


2. flask_login 플라스크 로그인 모듈 사용하기

https://flask-login.readthedocs.io/en/latest/

추가 설치가 필요한 모듈로

가장 많이 사용하는 클래스 LoginManager()을 사용한다.

from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app)

여기서 app은 플라스크앱이다.

다음 user_loader()함수를 데코레이터로 불러온다.

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

로그인 창에서 로그인하기

@app.route('/login', methods=['GET', 'POST'])
def login():
    # Here we use a class of some kind to represent and validate our
    # client-side form data. For example, WTForms is a library that will
    # handle this for us, and we use a custom LoginForm to validate.
    form = LoginForm()
    if form.validate_on_submit():
        # Login and validate the user.
        # user should be an instance of your `User` class
        login_user(user)

        return flask.redirect(url_for('index'))
    return flask.render_template('login.html', form=form)

사용자가 입력을 다한 후에 로그인 버튼이 눌렸다면

login_user(user)

을 이용해 로그인이 되도록한다.

여기서 user은 아래처럼 사용자db에 저장된 이메일과 사용자가 입력한 이메일과 일치한 유일한 레코드를 가져온다.

user = User.query.filter_by(email=email).first()

로그인이 성공하면 메인홈페이지로 돌아가게된다.

아닌 경우 다시 로그인 페이지로 돌아간다.


3. Flash

경고나 메세지를 알려주기 위한 모듈로 플라스크내에 있다.

예를 들어서

from flask import Flask, flash, redirect, render_template, \
     request, url_for

app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'

@app.route('/')
def index():
    return render_template('index.html')

위처럼 모듈을 불러와서 flash("보낼 메세지")

만일 로그인할 때

@app.route('/login', methods=["GET", "POST"])
def login():
    if request.method == "POST":
        email = request.form.get('email')
        password = request.form.get('password')

        user = User.query.filter_by(email=email).first()
        # 등록된 이메일이 없는 경우
        if not user:
            flash("등록되지 않은 이메일입니다, 다시 시도하시거나 새로 등록해주세요")
            return redirect(url_for('login'))
        # 등록된 이메일은 있으나 비밀번호가 맞지않은 경우
        elif not check_password_hash(user.password, password):
            flash('비밀번호가 틀렸습니다, 다시 입력해주세요.')
            return redirect(url_for('login'))
        # 등록된 이메일이고 비밀번호가 맞은 경우
        else:
            login_user(user)
            #로그인된다.
            return redirect(url_for('secrets'))

    return render_template("login.html")

위에 2. werkzug에서 check_password_hash(데이터베이스의비밀번호,사용자가입력한비밀번호) 을 이용한다.