Old Branch

Vue.js & Flask 로그인/로그아웃 (2) - Flask Auth API 만들기

woolbro 2020. 8. 21. 11:20
반응형

이전 글 첨부

[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을 추가 해 주도록 하려고 한다.