안 쓰던 블로그

[파이썬 Flask] 로그인, 로그아웃 만들기(session) 본문

언어/파이썬

[파이썬 Flask] 로그인, 로그아웃 만들기(session)

proqk 2020. 9. 6. 13:30
반응형

foxtrotin.tistory.com/269

 

[파이썬 Flask] 회원가입 웹 시스템 만들기

Flask 플라스크는 파이썬으로 웹 어플리케이션을 구현할 때 사용하는 프레임워크다 파이썬 웹 프로그래밍 프레임워크 중 잘 알려진 것이 django와 flask이다 쟝고는 여러 모듈과 기능을 제공하여 무

foxtrotin.tistory.com

foxtrotin.tistory.com/270

 

[파이썬 Flask] 회원가입 웹 시스템 만들기_2 WTF 적용하기

foxtrotin.tistory.com/269 [파이썬 Flask] 회원가입 웹 시스템 만들기 Flask 플라스크는 파이썬으로 웹 어플리케이션을 구현할 때 사용하는 프레임워크다 파이썬 웹 프로그래밍 프레임워크 중 잘 알려진 �

foxtrotin.tistory.com

 

쿠키와 세션

쿠키와 세션은 클라이언트와 서버가 주고 받는다

 

쿠키는 시간이 지나면 소멸하고, 서버 자원을 쓰지 않고 클라이언트쪽에 텍스트 파일 형태로 저장된다

보통 자동 로그인이나 팝업 창의 "오늘 이 창을 더 보지 않기"같은 기능을 위해 사용한다

 

세션과 관련된 데이터는 서버에 저장되며 서버에서 관리할 수 있다는 점에서 안전성이 좋다

보통 로그인과 같은 보안이 필요한 기능을 쓰고자 하면 세션을 사용한다

 

플라스크에서는 세션을 key값을 통해 value를 불러오는 딕셔너리 형태로 제공한다

따라서 회원가입을 만들고, 회원가입 때 받아두었던 DB의 id, pw필드와 세션이 일치하는지 확인하는 식으로 로그인 기능을 구현할 수 있다

추가로 로그아웃은 pop이나 remove으로 세션을 제거 하면 된다

 


먼저 login.html 만든다

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset='utf-8' />
        <meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no' />
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
        <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    </head>
<body>
    <div class = "container">
        <div class="row mt-5">
            <h1>로그인</h1>
        </div>

        <div class="col-12">
            <br><br>
            <form method="POST">
                {{form.csrf_token}}
                <div class="form-group">
                    {{form.userid.label("아이디")}}
                    {{form.userid(class="form-control", placeholder="아이디")}}
                </div>
                <div class="form-group">
                    {{form.password.label("비밀번호")}}
                    {%if form.password.errors%} <!--로그인이 실패하면-->
                    {{form.password.errors.0}} <!--첫번째 에러메시지 출력한다-->
                    {%endif%} <!--실패하지 않았으면 비밀번호 넘긴다-->
                    {{form.password(class="form-control", placeholder="비밀번호")}}
                </div>
                <button type="submit" class="btn btn-primary">제출</button>
            </form>
        </div>
    </div>
</body>
</html>

 

app.py

import os #디렉토리 절대 경로
from flask import Flask
from flask import render_template #template폴더 안에 파일을 쓰겠다
from flask import request #회원정보를 제출할 때 쓰는 request, post요청 처리
from flask import redirect #리다이렉트
#from flask_sqlalchemy import SQLAlchemy
from Models import db
from Models import User
from flask import session #세션
from flask_wtf.csrf import CSRFProtect #csrf
from Forms import RegisterForm, LoginForm
app = Flask(__name__)

@app.route('/')
def mainpage():
    userid = session.get('userid',None)
    return render_template('main.html', userid=userid)
    

@app.route('/register', methods=['GET', 'POST']) #GET(정보보기), POST(정보수정) 메서드 허용
def register():
    form = RegisterForm()
    if form.validate_on_submit(): #유효성 검사. 내용 채우지 않은 항목이 있는지까지 체크
        usertable = User() 
        usertable.userid = form.data.get('userid')
        usertable.email = form.data.get('email')
        usertable.password = form.data.get('password')

        db.session.add(usertable) #DB저장
        db.session.commit() #변동사항 반영
        
        return "회원가입 성공" 
    return render_template('register.html', form=form) #form이 어떤 form인지 명시한다

@app.route('/login', methods=['GET','POST'])  
def login():
    form = LoginForm() #로그인폼
    if form.validate_on_submit(): #유효성 검사
        print('{}가 로그인 했습니다'.format(form.data.get('userid')))
        session['userid']=form.data.get('userid') #form에서 가져온 userid를 세션에 저장
        return redirect('/') #성공하면 main.html로
    return render_template('login.html', form=form)

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

if __name__ == "__main__":
    #데이터베이스---------
    basedir = os.path.abspath(os.path.dirname(__file__)) #현재 파일이 있는 디렉토리 절대 경로
    dbfile = os.path.join(basedir, 'db.sqlite') #데이터베이스 파일을 만든다

    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + dbfile
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True #사용자에게 정보 전달완료하면 teadown. 그 때마다 커밋=DB반영
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False #추가 메모리를 사용하므로 꺼둔다
    app.config['SECRET_KEY']='asdfasdfasdfqwerty' #해시값은 임의로 적음

    csrf = CSRFProtect()
    csrf.init_app(app)

    db.init_app(app) #app설정값 초기화
    db.app = app #Models.py에서 db를 가져와서 db.app에 app을 명시적으로 넣는다
    db.create_all() #DB생성

    app.run(host="127.0.0.1", port=5000, debug=True)

/login 과 /logout을 추가한다

로그인은 세션에 userid를 등록하는 식이고, 로그아웃은 세션에서 userid를 삭제한다

session변수에 값을 저장하면 알아서 클라 정보를 구분해 줘서 편리하다

 

메인 페이지에다가 세션에서 userid이름을 가져오는 부분을 추가한다

userid정보는 main.html에다가 전달하여 로그인 성공 시 표시될 것이다

 

Forms.py

from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms import PasswordField
from wtforms.validators import DataRequired, EqualTo
from Models import User #Models.py 가져옴

class RegisterForm(FlaskForm):
    userid = StringField('userid', validators=[DataRequired()])
    email = StringField('email', validators=[DataRequired()])
    password = PasswordField('password', validators=[DataRequired(), EqualTo('password_2')]) #비밀번호 확인
    password_2 = PasswordField('password_2', validators=[DataRequired()])

class LoginForm(FlaskForm):
    class UserPassword(object):
        def __init__(self, message=None):
            self.message = message
            
        def __call__(self, form, field):
            userid = form['userid'].data
            password = field.data
            
            usertable = User.query.filter_by(userid=userid).first()
            if usertable.password != password:
            	raise ValueError('비밀번호 틀림')
                
    userid = StringField('userid', validators=[DataRequired()])
    password = PasswordField('password', validators=[DataRequired(), UserPassword()])

wtf패키지를 이용한 form을 생성해서 유효성을 검사한다

 

main.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset='utf-8' />
        <meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no' />
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
        <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    </head>
<body>
    <div class = "container">
        <div class="row mt-5">
            <h1>이곳은 메인 페이지</h1>
        </div>
        <br>
        <div class=form-group>
            {%if userid%}
            {{userid}}<a>님 안녕하세요!</a><br>
            <a href="/logout">로그아웃</a>
            {%endif%}
        </div>
    </div>
</body>
</html>

app.py에서 넘어온 userid가 있다면 userid 님 안녕하세요! 를 출력한다

/logout을 연결해 준다

 

 

이제 실행하고 /login으로 이동

틀리면 틀렸다고 뜬다

 

맞으면 메인화면으로 온다

 

로그아웃을 하면 로그인했던 정보가 사라진다

반응형
Comments