on
187일차 백엔드 Flask - flask_login, User class, 배포
187일차 백엔드 Flask - flask_login, User class, 배포
//==========flask_login란?==========
사용자를 체크하는 기능을 담당하는 라이브러리
예시)
사용자가 로그인시, flask_login 라이브러리를 사용하면, 사용자 관련 session 정보를 HTTP response에 넣어서 보내주고, 이를 기반으로 flask 서버에서 사용자를 구별할 수 있는 기능을 제공한다. //==========flask_login 주요 동작 방식========== 사용자가 로그인하면, 로그인 정보를 User class에서 객체로 가져오고, LoginManager()에 추가하여 세션 생성 flask 서버가 리턴시에 해당 세션 정보를 웹페이지에 송부 current_user 객체에 해당 객체가 저장됨 주요 attribute(속성) => 1. current_user.id : 사용자 ID (unicode로 된 값, python string이라고 봐도 됨) => - python3는 기본적으로 unicode를 사용 => 2. current_user.is_authenticated : 사용자가 로그인되었는지를 나타내는 값(True or False) => 이외의 attribute는 User class를 정의하면서, 필요에 따라 추가하면 됨 로그인 후 웹페이지로 flask 서버 접근 시, 전달받은 세션 정보를 기반으로 접근 세션 정보에서 id를 추출해서, LoginManager()에서 다루는 id일 경우, @login_required로 데코레이터가 추가된, API접근을 허용한다. 사용자가 로그아웃 시, LoginManager()에서 해당 id 제거 //==========문제는 User class 구현 예시가 많지 않음========== 즉, 각자의 아키텍쳐 기반 하에 생성이 필요하다. User class에는 flask_login 라이브러리의 UserMixin 클래스를 상속받아서 구현하는 것만 가이드 //==========flask_login User class가 지원해야할 변수/함수들========== is_authenticated : This property should return True if the user is autenticated
(사용자가 인증 된 경우, 이 속성은 True를 반환해야 한다.) is_active : This property should return True if this is an active user (계정 중지된 사용자 확인)
(활성화 된, 사용자인 경우에, 이 속성은 True를 반환해야 한다.) is_anonymous: This property should return True if this is an anonymous user
(익명 사용자인 경우에, 이 속성은 True를 반환) get_id(): This method must return a unicode that uniquely identifies this user, and can be used to load the user from the user_loader callback
(이 함수는 사용자를 고유 식별하는 유니코드를 반환해야 하며, user_loader 콜백에서 사용자를 로드할 때, 사용할 수 있다.)
UserMixin 클래스 상속시 관련 기본 변수/함수가 상속되고, 필요시에만 override 하면 됨
//==========flask_login 코드 구현==========
flask_login 초기 설정 코드
세션 generation(생성)을 위해, flask에서 secret key를 정의해줘야 한다. app.secret_key = os.urandom(24) flask_login 라이브러리에서 세션 관리 다음 코드에서 "strong"옵션을 사용할 시, Session 보안 적용 login_manager = LoginManager() login_manager.init_app(app) login_manager.session_protection = "strong"
사용자 session 생성
User 클래스를 기반으로 사용자 객체를 생성한 후, flask_login.login_user()) 함수에 해당 객체를 넣어주면, 해당 사용자 기반 session이 생성된다. 해당 세션은 HTTP response(응답)에 넣어져서 사용자 웹 브라우저에 송부된다. HTTP Response에 Set-Cookie 옵션에 해당 세션정보를 넣어서 송부하면,
사용자 웹 브라우저에서는 추후 해당 서버 주소로 HTTP request 송부 시, 해당 session 정보를 자동으로 넣어서 요청한다.
flask_login은 HTTP request(요청)에서 자동으로 session 정보를 가져와서, 사용자를 구분한다. 세션 생성 시, 사용자 HTTP request에 들어 있는 사용자 IP address와 user agent 등을 함께 참조해서, 세션을 생성하므로, 다른 사용자가 세션을 탈취하더라도, 사용자 IP address와 user agent까지 동일하게 request에 넣어서 요청해야 하고,
이 경우, 이에 대한 응답은 다른 컴퓨터의 사용자가 아닌, 해당 사용자 IP로 전송되므로, session 보안에 유용하다. from flask_login import login_user user = User.create(user_email, blog_id) login_user(user)
login_manager 관련 사전 선언 필요 함수 (다음 두 함수는 사전 선언이 필요)
로그인 후 최초 current_user 호출 시, 다음 코드 호출 사용자 정보를 flask_login과 함께 사용되는 User class를 통해 가져옴 @login_manager.user_loader def load_user(user_id): return User.get(user_id) @login_required(필요) 데코레이터로 로그인 후, 접근 가능한 페이지 protection(보호) 가능 로그인이 안된 채로 해당 페이지 접근 시, @login_manager.unauthorized_handler(승인 받지 못함)에 정의된 함수를 호출하므로, 필요 시 구현. 원하는 형태로 구현 가능. //==========User class 구현========== User class는 UserMixin class를 상속해야 한다. 속성으로 사용자를 구분할 수 있는 id를 반드시 가지고 있어야 한다.
class User(UserMixin):
def init(self, user_id, user_email, blog_id):
self.id = user_id
self.user_email = user_email
self.blog_id = blog_id
def get_id(self):
return str(self.id)
@staticmethod
def get(user_id):
mysql_db = conn_mysqldb()
db_cursor = mysql_db.cursor()
sql = "SELECT * FROM user_info WHERE USER_ID = '" + str(user_id) + "'"
db_cursor.execute(sql)
user = db_cursor.fetchone()
if not user:
db_cursor.close()
return None
print(user) user = User(user_id=user[0], user_email=user[1], blog_id=user[2]) db_cursor.close() return user
@staticmethod
def find(user_email):
mysql_db = conn_mysqldb()
db_cursor = mysql_db.cursor()
sql = "SELECT * FROM user_info WHERE USER_EMAIL = '" + str(user_email) + "'"
db_cursor.execute(sql)
user = db_cursor.fetchone()
if not user:
db_cursor.close()
return None
print(user) user = User(user_id=user[0], user_email=user[1], blog_id=user[2]) db_cursor.close() return user
@staticmethod
def create(user_email, blog_id):
mysql_db = conn_mysqldb()
db_cursor = mysql_db.cursor()
sql = "INSERT INTO user_info (USER_EMAIL, BLOG_ID) VALUES ('%s', '%s') % (str(user_email), str(blog_id))
db_cursor.execute(sql)
user = db_cursor.fetchone()
if not user:
db_cursor.close()
return None
print(user) user = User(user_id=user[0], user_email=user[1], blog_id=user[2]) db_cursor.close() return user //==========배포 (deployment)==========
클라우드 서비스(AWS)를 사용하여, 리눅스 기반 서버에 docker 기반 배포가 가장 일반적인 형태이다. 이를 위해서는 클라우드 서비스(AWS) 사용버, 리눅스 사용법, docker 사용법을 익혀야 한다. 이외에 클라우드 서비스(AWS) 기능과 파이썬을 사용하여, 자동 배포 기능을 구현한다. //==========초간단 웹서비스 배포========== ngrok를 통해, 자신의 PC에서 동작하는 웹서버를 외부에서도 접속할 수 있도록 할 수 있다. //==========AWS에서 실제 배포 기술로 배포하기==========
AWS에서 실제 배포하는 기술은 리눅스, AWS 등에 매우 익숙해야 하며, 각 환경에 따라 문제 발생시에도 각 문제 사항을 스스로 해결할 수 있는 기술력을 갖춘 상태에서만 배포가 가능하다. https://aws.amazon.com/ -> My Account -> AWS Management Console -> Region (Seoul) EC2 -> Launch Instance -> Ubuntu Server 16.04 ->t2.micro -> pem파일 다운로드 (로컬PC에 ~/.ssh/에 저장) https://medium.com/flearning-edu/aws-ec2-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0-ed5d28cd875a Elastic IP Go Elastic IP -> Allocate New Address
Action -> Associate Address -> Select Instance Private IP: Private IP Address는 설정된 그대로! 172.x.x.x 로 설정된 클라우드 내부 IP를 52.x.x.x 공개 IP로 연결하겠다는 것 요금불안: http://gun0912.tistory.com/45 , https://aws.amazon.com/ko/free/ //==========EC2에 접속하는 방법==========
서버 접속 방법 osx chmod 400 [pem_file]
ssh -i path/[pemfile] ubuntu@[aws_server_public_ip] windows 윈도우즈에서 접속하기 링크(http://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/putty.html)
putty(ssh client), puttygen download (https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html)
서버 터미널 접속 방법
osx chmod 400 [pem_file]
ssh -i path/[pemfile] ubuntu@[aws_server_public_ip] windows 윈도우즈에서 접속하기 링크(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/putty.html)
putty(ssh client), puttygen download (http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html)
서버 FTP 접속 방법
FileZilla FTP 프로그램 사용 윈도우: http://hyeonstorage.tistory.com/272
맥: http://devgyugyu.tistory.com/8 //==========EC2 서버에 apache 웹서버 설치========== sudo apt-get update -y sudo apt-get install apache2 sudo a2enmod rewrite sudo service apache2 restart 현재 아파치 실행 상태 확인 명령: sudo service apache2 status
//==========FTP 접속 및 웹페이지 업로드==========
Fizilla 접속 설정 참고: https://babamba-playground.tistory.com/27 FTP 접속 - web 디렉토리 만들기 - upload SSH 접속 후 cd web
sudo cp -rf * /var/www/html/ //==========EC2 서버에 anaconda 설치========== anaconda 다운로드: https://www.anaconda.com/products/individual FTP 연결 및 해당 파일 업로드 다음 명령으로 설치 (파일명은 다운로드 시점마다 다를 수 있음) 라이센스 동의 (yes), 설치 위치 (Enter) sudo bash Anaconda3-2020.07-Linux-x86_64.sh anaconda 는 다음 디렉토리에 설치 /home/ubuntu/anaconda3 참고: https://docs.anaconda.com/anaconda/install/linux/ //==========apache2 설정========== 8081 포트 추가 AWS EC2 설정에서도 해당 포트 추가
아파치 설정에서도 다음과 같이 8081 포트 추가
sudo vi /etc/apache2/ports.conf Listen 80
Listen 8081 # 추가 가상호스트 추가 kwon.org 를 자신의 서버 IP로 변경하면 됨 sudo vi /etc/apache2/sites-available/000-default.conf
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerAdmin [email protected] ServerName kwon.org ServerAlias www.kwon.org # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, # error, crit, alert, emerg. # It is also possible to configure the loglevel for particular # modules, e.g. #LogLevel info ssl:warn ErrorLog /home/ubuntu/web/backend/error.log CustomLog /home/ubuntu/web/backend/access.log combined WSGIDaemonProcess runserver python-path=/home/ubuntu/anaconda3 user=ubuntu group=ubuntu threads=5 WSGIProcessGroup runserver WSGIScriptAlias / "home/ubuntu/web/backend/runserver.wsgi" Require all granted
apache2 재실행 sudo service apache2 restart
from http://kwonputer.tistory.com/210 by ccl(A) rewrite - 2021-03-19 21:26:22