login / restful api / login 부분 구현 / 추가
tko22/flask-boilerplate 에 login 부분 추가
tko22/flask-boilerplate(tko22) 는 Rest Api server 에 맞는 구조이다. 그래서(?) login 부분이 들어가 있지 않다. 그래서 hack4impact/flask-base(hack4impact) 에 구현되어 있는 login 부분을 tko22/flask-boilerplate 의 구조에 맞춰서 변경했다.
절차
- diff-add-login-v3.zip: 코드의 변경사항을 확인할 수 있다.
pip install Flask_Login
pip install webargs
- api/models/user.py 추가
api/models/user.py
에 user table 의 model 생성api/models/__init__.py
에from .user import *
추가
- Flask-Login setup
- flask 에 LoginManager 추가:
api/__init__.py
에서 LoginManager() 추가
- flask 에 LoginManager 추가:
api/views/main.py
에 login api 추가
hack4impact에서는 Flask_Login
을 사용하기 때문에 먼저 Flask_Login 을 설치한다. 그리고 parameter validate 를 하기 위해서 webargs
package 를 설치한다.
user.py
로그인과 관련한 user 의 정보를 가진 user table 에 대한 model 을 생성한다. 그리고 이것에 대한 import 를 편하게 하기 위해서 init.py 에 import 를 해놓자.
더불어 flask-login 에서 필요로 하는 몇가지를 추가해야 한다. 그렇지 않으면 api request 가 제대로 동작하지 않는다.
# /api/models/user.py
from api.core import Mixin
from .base import db
from flask_login import UserMixin
class UserAccounts(UserMixin, db.Model):
__tablename__ = "user_accounts"
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String)
encrypted_password = db.Column(db.String)
created_at = db.Column(db.DateTime)
updated_at = db.Column(db.DateTime)
def __init__(self, **kwargs):
super(UserAccounts, self).__init__(**kwargs)
# if self.role is None:
# if self.email == current_app.config["ADMIN_EMAIL"]:
# self.role = Role.query.filter_by(
# permissions=Permission.ADMINISTER
# ).first()
# if self.role is None:
# self.role = Role.query.filter_by(default=True).first()
def verify_password(self, password):
# return check_password_hash(self.password_hash, password)
return self.encrypted_password == password
def __repr__(self):
return "<User '%s'>" % self.full_name()
# flask-login setup
class AnonymousUser(AnonymousUserMixin):
def can(self, _):
return False
def is_admin(self):
return False
login_manager.anonymous_user = AnonymousUser
@login_manager.user_loader
def load_user(user_id):
return UserhabitAccounts.query.get(int(user_id))
# /api/models/__init__.py
from .user import *
Flask-Login setup
api/__init__.py
에서 flask app 을 만들게 되는데, 이때 LoginManager를 추가해 줘야 한다.
# Set up Flask-Login
login_manager = LoginManager()
login_manager.session_protection = "strong"
login_manager.login_view = "account.login"
...
def create_app(test_config=None):
...
login_manager.init_app(app)
...
login api
이제 실체 login 부분을 만들어 보자. api/views/main.py
에 api 를 추가한다.
...
from flask_login import login_user
from api.models import UserAccounts
from webargs.flaskparser import parser
# visit /login
# for validator,
# https://marshmallow.readthedocs.io/en/latest/marshmallow.validate.html#module-marshmallow.validate
@main.route("/login", methods=["POST"])
@parser.use_args(
{
"email": fields.String(required=True, validate=validate.Email()),
"password": fields.String(required=True),
},
location="json",
)
def post_login(args):
user = (
UserAccounts.query
.filter(UserAccounts.email == args["email"])
.first()
)
if (
user is not None
and user.encrypted_password is not None
and user.verify_password(args["password"])
):
login_user(user)
return create_response(
message="You are now logged in. Welcome back!"
)
return create_response(
status=422, message="아이디 패스워드를 확인해주세요."
)
test
아래처럼 curl 을 날리면 된다. 아래는 windows curl 이다.
curl -X POST -H "Content-Type: application/json" -d "{\"email\":\"test@gmail.com\",\"password\":\"ddkjfkdlsjltehthp\"}" http://127.0.0.1:5000/login
webargs 이용시, error response 를 json 형식으로
- Handling Application Errors — Flask Documentation (2.0.x)
- Framework Support — webargs 8.0.0 documentation
400, 422 error 가 발생할 때 json 형식으로 response 를 주게 된다.
from flask import jsonify
# Return validation errors as JSON
@app.errorhandler(422)
@app.errorhandler(400)
def handle_error(err):
headers = err.data.get("headers", None)
messages = err.data.get("messages", ["Invalid request."])
if headers:
return jsonify({"errors": messages}), err.code, headers
else:
return jsonify({"errors": messages}), err.code
댓글 없음:
댓글 쓰기