TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 웹개발>

[파이썬] 플라스크(Flask) - 인증과 세션(1)

by 기록자_Recordian 2024. 7. 20.
728x90
반응형
시작에 앞서
해당 내용은 <가장 빠른 풀스택을 위한 Flask & FastAPI>, Dave Lee 지음. BJ Public 출판.
내용을 토대로 작성되었습니다. 보다 자세한 사항은 해당 교재를 참고하시기 바랍니다.

인증과 세션

 

인증(authentication)

사용자가 누구인지 확인하는 과정

대체로 로그인 페이지에서 이 과정이 이루어지며, 사용자는 일반적으로 ID와 비밀번호를 제공한다.

시스템은 이 정보를 데이터베이스와 비교하여 해당 사용자가 정당한 사용자인지 아닌지를 판단한다.

 

세션(session)

사용자가 웹사이트에 접속한 이후부터 로그아웃하거나 브라우저를 닫을때까지 유지되는 정보의 집합이다.

세션을 통해 사용자는 한 번 로그인하면 다시 로그인하지 않고도 다른 페이지를 자유롭게 이동할 수 있다.

세션 정보는 서버 측과 클라이언트 측 쿠키에 저장하는 것이며, 서버 측에서는 일반적으로 데이터베이스나 캐시 시스템에 세션 정보를 저장한다.

 

인증을 통해 사용자의 정체성을 확인한 후 세션을 통해 그 사용자의 상태를 계속 추적한다.


플라스크에서의 인증과 세션

 

플라스크에서는 Flask-Login과 같은 확장을 사용하여 인증을 쉽게 구현할 수 있고,

플라스크 자체적으로 세션을 관리하는 기능을 제공하므로 별도의 세션 관리 라이브러리 없이도 기본적인 세션 관리가 가능하다.

 

플라스크에서 세션은 기본적으로 클라이언트 측 쿠키에 저장된다.

이 쿠키는 암호화되어 있어 사용자가 직접 수정하기는 어려우며, 서버 측에서는 이 쿠키를 해독하여 사용자의 상태를 파악한다.


Flask-Login을 사용한 인증

 

설치(터미널)

pip install Flask-Login==0.6.3


플라스크 애플리케이션에 LoginManager를 초기화

from flask_login import LoginManager

# LoginManager 인스턴스 생성
Login_manager = LoginManager()
# Flask 애플리케이션과 LoginManager 인스턴스 연결
Login_manager.init_app(app)
  • LoginManager 클래스는 사용자의 로그인 상태를 관리하기 위한 여러 메서드와 속성 제공
  • login_manager.init_app(app): LoginManager 인스턴스를 현재의 플라스크 애플리케이션에 연결하는 과정

Flask-Login을 사용하기 위해서는 사용자 정보를 담을 클래스가 필요하고, 이 클래스는 UserMixin을 상속받아야 한다.

from flask_login import UserMixin
class User(UserMixin, db.Model):
    # 각 컬럼 정의
    id = db.Column(db.Integer, primary_key=True) # 사용자 id 기본키로 설정
    username = db.Column(db.String(80), unique=True, nullable=False) # 사용자 이름, 중복 불가 및 필수 입력
    password = db.column(db.String(128))
  • UserMixin: Flask-Login 에서 제공하는 기본 사용자 모델. 로그인 관리에 필요한 메서드를 포함한다
  • 이 클래스는 데이터베이스 모델이면서 UserMixin을 상속받아 Flask-Login 과 호환된다

@login_manager.user_loader 데코레이터를 사용하여 사용자를 로드하는 함수를 정의

@login_manager.user_loader 데코레이터는 login_manager = LoginManager() 코드에서 만들어진다.

즉, 이 변수 이름이 바뀌면 뒤이어 나오는 데코레이터 사용을 위해서도 동일한 이름을 사용해야 한다.

 

만약, login_manager 대신 auth_manager로 변수명을 변경한다면,

데코레이터 역시 @auth_manager.user_loader로 변겅되어야 한다.

# 사용자 로드 함수에 데코레이터 적용
@Login_manager.user_loader
def load_user(user_id):
    # 주어진 user_id로 사용자 조회 후 반환
    return User.query.get(int(user_id))
  • @login_manager.user_loader 데코레이터는 Flask-Login에게 어떻게 사용자 객체를 로드할지 알려준다
  • load_user 함수는 세션에 저장된 사용자 ID를 기반으로 사용자 객체를 데이터베이스에서 조회한다. Flask-Login 은 로그인 관리를 위해 이 함수를 내부적으로 사용한다
[대략적인 흐름]
플라스크 애플리케이션이 시작할 때, LoginManager를 초기화하고 플라스크 애플리케이션에 등록
▶ 사용자 클래스를 정의하며, 이 클래스는 로그인 관리를 위해 UserMixin 을 상속
▶ 사용자 ID를 받아 데이터베이스에서 해당 사용자를 찾아 반환하는 load_user 함수를 정의
▶ @login_manager.user_loader 데코레이터는 Flask-Login에게 사용자 로딩 매커니즘 제공

예제로 이해하는 인증

 

MySQL 데이터베이스에 flaskdb 이름의 데이터베이스 생성 후, 아래의 전체 코드 입력

CREATE DATABASE flaskdb;
from flask import Flask, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
import pymysql
from flask_migrate import Migrate
from flask_login import LoginManager, login_required, login_user, logout_user, UserMixin, current_user

app = Flask(__name__)
# 데이터베이스 연결 URI 설정
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:pw@localhost:3306/db_name'
# mysql://root:[비밀번호]@localhost:[root번호]/[db이름]
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Flask 애플리케이션을 위한 비밀 키 설정
app.config['SECRET_KEY'] = 'mysecretkey'

# SQLAlchemy 인스턴스 생성
db = SQLAlchemy(app)
migrate = Migrate(app, db)  # Flask-Migrate 설정

# LoginManager 인스턴스 생성
login_manager = LoginManager() # Flask 애플리케이션과 LoginManager 인스턴스 연결
login_manager.init_app(app) # 애플리케이션에 LoginManager 적용
login_manager.login_view = 'login' # 로그인 페이지의 뷰 함수 이름 설정

# 사용자 모델 정의
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True) # 사용자 id 기본키로 설정
    username = db.Column(db.String(80), unique=True, nullable=False) # 사용자 이름, 중복 불가 및 필수 입력
    email = db.Column(db.String(120), unique=True, nullable=False) # 이메일 주소, 중복 불가 및 필수 입력
    password = db.Column(db.String(128), nullable=False) # 사용자 비밀번호, 필수 입력
    
    def __repr__(self):
        return f'<User {self.username}>' # 객체를 문자열로 표현할 때 사용할 형식

# 애플리케이션 컨텍스트 안에서 데이터베이스 테이블 생성
with app.app_context():
    db.create_all()

# 사용자 로드 함수에 데코레이터 적용
@login_manager.user_loader
def load_user(user_id):
    # 주어진 user_id로 사용자 조회 후 반환
    return User.query.get(int(user_id))

@app.route('/')
def index():
    return 'Home Page'

@app.route('/protected')
@login_required # 로그인한 사용자만 액세스 가능
def protected():
    return f'Logged in as {current_user.username}' # 현재 로그인한 사용자의 이름 표시

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
        # 데이터베이스에서 사용자 조회
        if user and user.password == password:
            login_user(user) # 사용자가 존재하고 비밀번호가 맞다면 로그인 처리
            return redirect(url_for('protected')) # 보호된 페이지로 리디렉션
        
    # 로그인 폼 HTML 반환
    return '''
        <form method="post">
            Username: <input type="text" name="username"><br>
            Password: <input type="password" name="password"><br>
            <input type="submit" value="Login">
         </form>   
    '''    

@app.route('/logout')
@login_required # 로그인한 사용자만 액세스 가능
def logout():
    logout_user() # 현재 사용자 로그아웃 처리
    return redirect(url_for('index')) # 홈페이지로 리디렉션

@app.route('/create_test_user')
def create_test_user():
    test_user = User(username='testuser', email='test@example.com', password='testpassword') # 테스트 사용자 생성
    db.session.add(test_user)
    db.session.commit() # 데이터베이스에 테스트 사용자 추가
    return 'Test user created' # 사용자 생성 완료 메시지 반환

 

터미널에서 flask run 명령을 수행하고 각각의 사이트에 접속하여 테스트 

 

로그인을 하지 않고 /protected 에 접속하려고 하면 로그인이 필요하다는 화면이 뜬다.


다음 내용

 

[파이썬] 플라스크(Flask) - 인증과 세션(2)

시작에 앞서해당 내용은 , Dave Lee 지음. BJ Public 출판.내용을 토대로 작성되었습니다. 보다 자세한 사항은 해당 교재를 참고하시기 바랍니다.이전 내용 [파이썬] 플라스크(Flask) - 인증과 세션시작

puppy-foot-it.tistory.com

 

728x90
반응형

Recordian, 기록의 힘을 믿는다.