로그인 시 세션 정보를 넘겨주고 싶었다.
기존 Flask 에 존재하는 session 은 클라이언트 측에 세션을 저장하는 방식이므로 매우 위험하다.
from flask import session
flask-session
하지만 플라스크 라이브러리 중 flask-session 을 설치하고 app에 설정해주면 해당 session은 서버측에 저장되게 된다.
from flask_session import Session
server_session = Session(app)
이때 꼭 정해야 하는 app config 두 가지는 SECRET_KEY 와 SESSION_TPYE 이다. app 에 여러 설정 들이 늘어나면서 app.py 가 더러워져서 클래스로 분리시켜 주었다.
import os, dotenv
dotenv.load_dotenv()
class ApplicationConfig:
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True
SQLALCHEMY_DATABASE_URI = f'postgresql://{os.getenv('PG_USER')}:{os.getenv('PG_PW')}@{os.getenv('PG_HOST')}:{os.getenv('PG_PORT')}/{os.getenv('PG_DBNAME')}'
SECRET_KEY = f'{os.getenv('SECRET_KEY')}'
BCRYPT_LEVEL = 10
SESSION_TYPE = 'filesystem'
app.config.from_object(ApplicationConfig)
위처럼 from_object() 메서드를 사용하면 ApplicationConfig 클래스 아래에 여러 app과 관련된 config 를 지정해주면 된다.
SESSION_TYPE 에는 여러 타입들이 존재한다. https://stackoverflow.com/questions/26080872/secret-key-not-set-in-flask-session-using-the-flask-session-extension
스택오버플로에서 확인하면 알 수 있듯이 가장 기본적으로 빠르게 구현하고자 한다면 filesystem 으로 설정해주면 된다. 일단은 파일 시스템으로 설정하고 결과값만 확인해준다.
위의 세션 쿠키의 value 에서 보이는 값이 세션ID 가 된다.
세션 타입의 파일시스템 방식은 서버측 루트 계층에 flask_session 폴더가 생기면서 로그인할 때 세션이 생긴다.
하지만 이렇게 무분별하게 서버에 세션이 쌓이면 좋지 않을 것이다. 여러 선택지가 있겠지만 이럴 때 redis 를 사용하면 좋다고 한다. 설정하는 방법은 아래 강의에서 확인하자.
https://youtu.be/sBw0O5YTT4Q?si=6eE161-3hegvjKzk
redis
key-value 기반의 메모리 DB로 메모리에 관리되므로 프로세스가 중단하거나 컴퓨터가 꺼지면 모든 데이터가 사라지는 속성이 있다.
레디스의 기본은 리눅스 환경이므로, 윈도우의 경우 https://github.com/microsoftarchive/redis/releases 여기서 다운로드 가능하다. 해당 zip 파일을 압축 풀고 redis-server.exe 를 실행시키면 서버가 구동될 것이다.
redis-cli.exe 를 실행하면 레디스 커맨드 라인을 볼 수 있다. 이렇게 매번 켜는 것은 번거로울 것이다. 그래서 첨부했던 강의에서는 .msi 파일을 다운받아서 실행해주었다. 설치 가능하게끔 나오고 환경변수 설정만 체크해준다. 정상적으로 설치됐다면 아래와 같이 cmd 창에 redis-cli 로 접근하여 바로 redis-cli.exe 에 접근 가능해진다.
보다시피 세션을 설정해주면 위처럼 keys * 로 확인이 가능하다.
로그인과 로그아웃을 완료하였다. 클라이언트에 요청할 때 꼭 credentials 를 True로 해주자. 이 부분 때문에 이틀을 날려버렸다 (ㅋㅋ;;;)
@LogNS.route('/login')
class Login(Resource):
def post(self):
"""로그인 요청"""
login_info = request.json['user_info']
try:
user = User.query.filter(User.user_email == login_info.get('email')).one()
if user is None:
return jsonify({'message':'No Email'})
is_decoded_pw = user.check_pw(login_info.get('pw'))
if is_decoded_pw:
# 세션 설정
session['userid'] = user.user_id
db.session.commit()
return jsonify({ 'message': 'OK' })
else:
return jsonify({'message': 'Password Invalid'})
except NoResultFound:
return jsonify({'message':'Fail', 'reason': 'NoResultFound'})
except MultipleResultsFound:
return jsonify({'message':'Fail' , 'reason': 'MultipleResultsFound'})
@LogNS.route('/session')
class GetSession(Resource):
def get(self):
userId = session.get('userid')
if not userId:
return jsonify({ 'isLogin' : False })
user = User.query.filter_by(user_id = userId).first()
return jsonify({
'isLogin' : True,
'id' : user.user_id,
'email' : user.user_email,
})
@LogNS.route('/logout')
class Logout(Resource):
def get(self):
session.pop('userid', None)
session.pop('useremail', None)
return jsonify({ 'message': 'OK' })
오늘도 우당탕탕 어떻게든 문제를 해결해나가고 있다.
'Python > Flask' 카테고리의 다른 글
SQLAlchemy - filter + 조회 예시 (0) | 2024.03.07 |
---|---|
Flask + PostgreSQL + React - 2 (1) | 2024.03.06 |
Flask + PostgreSQL + React - 1 (0) | 2024.03.05 |
Jinja2 and Werkzeug? (0) | 2024.03.04 |
flask 웹개발 기초 정리 - 3 (feat. SQLAlchemy) (1) | 2024.02.28 |