Vue.js & Flask 로그인/로그아웃 (2) - Flask Auth API 만들기
이전 글 첨부
[Master_branch/develop_branch] - Vue.js & Flask - 개발환경구축하기
[Master_branch/develop_branch] - Vue.js & Flask - 컴포넌트와 api 연동(1) - backend
[Master_branch/develop_branch] - Vue.js & Flask - 컴포넌트와 api 연동(2) - frontend
[Master_branch/develop_branch] - Vue.js & Flask - 데이터 주고받기 (axios)
[Master_branch/develop_branch] - Vue.js & Flask - 데이터 주고받기 axios(2) button binding
[Master_branch/develop_branch] - Vue.js & Flask 로그인/로그아웃 (2) - Flask Auth API 만들기
사용할 화면이 flask 서버 내에서 작성 된 것이 아닌 Vue.js에서 작성 된 것이기 때문에 flask서버에서는 api를 작성 해 주도록 할 것이다.
- 회원가입
- 로그인
- 로그아웃
Flask Login API - session
DB Create
- 데이터베이스를 미리 세팅하고 데이터를 하나 넣어주도록 하겠다
create table user(
id int(5) not null auto_increment,
username varchar(20) not null,
useremail varchar(100) default null,
userpwd varchar(100) not null,
bio text default null,
created_at datetime default current_timestamp,
updated_at datetime default current_timestamp on update current_timestamp,
primary Key(id,username)
)
INSERT INTO fullstack_test.`user`
(username, useremail, userpwd, bio, created_at, updated_at)
VALUES('wool', 'wool@gmail.com', 'qwerqwer123', '', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
User Model Setting
mysql을 사용하고 flask-sqlalchemy를 사용 하고 있다.
flask 모델에 맞게 연동된 데이터베이스를 생성 해 주려고 한다.
flask-sqlacodegen
flask-sqlacodegen은 모델을 생성 해 주는 툴이다. 다운받아 사용 할 것이다.
(venv)$ pip install flask-sqlacodegen
flask-sqlacodegen이라는 명령어로 실행 하면 된다.
-
사용법은 여러가지가 있다.
flask-sqlacodegen 사용법flask-sqlacodegen 해당하는 db를 바로 파일로 변환하기flask-sqlacodegen 해당 db의 특정 테이블만 변환하기flask-sqlacodegen 예제 $ flask-sqlacodegen "mysql+pymysql://root:qwer!@#123@localhost:3306/test_db" — flask > model.py
$ flask-sqlacodegen "[sql_class]://[username]:[password]@[DB_IP]/[DB_NAME]" — flask --table [table_name]> model.py
$ flask-sqlacodegen "[sql_class]://[username]:[password]@[DB_IP]/[DB_NAME]" — flask > model.py
$ flask-sqlacodegen "[sql_class]://[username]:[password]@[DB_IP]/[DB_NAME]" — flask
우리가 필요한 User 모델을 뽑아보도록 하겠다.
(venv)$ flask-sqlacodegen "mysql+pymysql://wool:qwerqwer123@localhost:3306/fullstack_test" --flask
User Class
backend
├── app.py
├── back.dev.Dockerfile
├── my_model
│ ├── __init__.py
│ └── user_model.py
├── my_provider
│ ├── __init__.py
│ ├── baseball_scrapper.py
│ └── movie_scrapper.py
├── my_util
│ ├── __init__.py
│ ├── __pycache__
│ └── my_logger.py
└── requirements.txt
my_model 패키지를 만들고, user_model.py를 만들어서 방금 생성된 유저 클래스를 저장 해 주도록 하겠다
user_model.py의 코드이다
# coding: utf-8
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True, nullable=False)
username = db.Column(db.String(20), primary_key=True, nullable=False)
useremail = db.Column(db.String(100))
userpwd = db.Column(db.String(100), nullable=False)
bio = db.Column(db.Text)
created_at = db.Column(db.DateTime, server_default=db.FetchedValue())
updated_at = db.Column(db.DateTime, server_default=db.FetchedValue())
Password Check - 생략해도 상관 없지만 하면 좋다....
비밀번호는 문자 그대로 저장하기보다 암호화 해서 저장하는 것이 좋다
암호화를 위해서 flask-bcrypt를 설치 해 주도록 하자
install flask-bcrypt
(venv)$ pip install flask-bcrypt
플라스크 앱에 bcrypt 추가
backend/app.py
...
import os, traceback
from flask_bcrypt import Bcrypt
# instantiate the app
app = Flask(__name__)
app.secret_key = 'laksdjfoiawjewfansldkfnzcvjlzskdf'
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("SQLALCHEMY_DATABASE_URI")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = os.getenv("SQLALCHEMY_TRACK_MODIFICATIONS")
db = SQLAlchemy()
db.init_app(app)
# enable CORS
CORS(app, resources={r'/*': {'origins': '*'}})
bcrypt = Bcrypt(app)
...
User Model에 비밀번호 암호화 적용
# coding: utf-8
from flask_bcrypt import generate_password_hash, check_password_hash
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True, nullable=False)
username = db.Column(db.String(20), primary_key=True, nullable=False)
useremail = db.Column(db.String(100))
userpwd = db.Column(db.String(100), nullable=False)
bio = db.Column(db.Text)
created_at = db.Column(db.DateTime, server_default=db.FetchedValue())
updated_at = db.Column(db.DateTime, server_default=db.FetchedValue())
def has_password(self):
self.userpwd = generate_password_hash(self.userpwd).decode('utf8')
def check_password(self,password):
return check_password_hash(self.userpwd,password)
- has_password 함수에서 암호화를 해준다
- check_password 함수에서 암호화 된 비밀번호와 입력받은 비밀번호를 비교 해 준다
- 적용은 회원가입 , 로그인에서 적용 해보도록 하자
User SignUp
- POST로 작성 해 준 데이터를 받아서 사용자를 저장한다
@app.route("/api/auth/signup", methods=['POST'])
def auth_signup():
my_logger.info("SignUp!")
my_logger.info(request.get_json())
data = request.get_json()
username = data.get('username')
useremail = data.get('useremail')
userpwd = data.get('userpwd')
bio = data.get('bio')
user_data = user_model.User.query.filter_by(username=username).first()
if user_data is not None:
my_logger.info("Username is Already exist")
return {"success": "username is already exist"}
try:
user = user_model.User(**data)
user.has_password()
user_model.db.session.add(user)
user_model.db.session.commit()
user_model.db.session.remove()
my_logger.info("user Save Success")
return {'success': 'user Save Success'}
except Exception as e:
my_logger.error("user Save Fail")
my_logger.debug(traceback.print_exc(e))
return {'fail': "user Save Fail"}
User Login
- POST로 로그인 사용자 정보를 받아와서 패스워드 체크를 해 준 후 로그인을 한다
@app.route("/api/auth/login", methods=['POST'])
def auth_login():
my_logger.info("User auth Login")
my_logger.info(request.get_json())
username = request.get_json()['username']
useremail = request.get_json().get('useremail')
userpwd = request.get_json()['userpwd']
my_user = user_model.User()
try:
user_data = my_user.query.filter_by(username=username).first()
if user_data is not None:
my_logger.info(user_data.userpwd)
auth = user_data.check_password(userpwd)
if not auth:
my_logger.info("password validation fail!")
return {'success': 'password validation fail'}
else:
my_logger.info("login success!")
session['login'] = True
return {'success': 'user Login Success!'}
else:
my_logger.info("user information is wrong or user does not exists....")
session['login'] = False
return {'success': 'user information is wrong or user does not exists....'}
except Exception as e:
my_logger.error("login Exception...")
my_logger.debug(traceback.print_exc(e))
session['login_session'] = False
return {'fail': 'login Exception...'}
User Logout
- 로그인 되어있는 현재 Session을 종료시킨다
@app.route('/api/auth/logout')
def auth_logout():
session['login'] = False
return {'success': 'logout'}
생각보다 길었지만, API로 인증받은 token까지 추가 해 주는 것이 목표이다.
다음 글에서는 token을 추가 해 주도록 하려고 한다.