시작에 앞서
해당 내용은 <가장 빠른 풀스택을 위한 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 에 접속하려고 하면 로그인이 필요하다는 화면이 뜬다.
다음 내용
'[파이썬 Projects] > <파이썬 웹개발>' 카테고리의 다른 글
[파이썬] 플라스크(Flask) - RESTful API (0) | 2024.07.21 |
---|---|
[파이썬] 플라스크(Flask) - 인증과 세션(2) (0) | 2024.07.21 |
[파이썬] 플라스크(Flask) - 데이터베이스 (3) (2) | 2024.07.20 |
[파이썬] 플라스크(Flask) - 데이터베이스 (2) (0) | 2024.07.18 |
[파이썬] 플라스크(Flask) - 데이터베이스 (1) (0) | 2024.07.16 |