From 7d6f98ffdae646f0357a8cb4d53909db6ef807b2 Mon Sep 17 00:00:00 2001 From: Daniel Lukats Date: Thu, 30 Jul 2020 17:23:01 +0200 Subject: [PATCH] added authorization, signup, login with jwt --- .gitignore | 2 ++ auth/__init__.py | 0 auth/auth.py | 43 +++++++++++++++++++++++++++++++++++++++++++ database/__init__.py | 3 +++ database/user.py | 8 ++++++++ main.py | 16 +++++++++++++--- requirements.txt | 4 +++- 7 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 auth/__init__.py create mode 100644 auth/auth.py create mode 100644 database/__init__.py create mode 100644 database/user.py diff --git a/.gitignore b/.gitignore index 614107f..9219425 100644 --- a/.gitignore +++ b/.gitignore @@ -214,3 +214,5 @@ dmypy.json .pytype/ # End of https://www.toptal.com/developers/gitignore/api/python,intellij + +*.sqlite \ No newline at end of file diff --git a/auth/__init__.py b/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/auth/auth.py b/auth/auth.py new file mode 100644 index 0000000..29d0f3a --- /dev/null +++ b/auth/auth.py @@ -0,0 +1,43 @@ +from flask import Blueprint, request +from flask_jwt_extended import create_access_token +from http import HTTPStatus +from werkzeug.security import check_password_hash, generate_password_hash + +from database import db +from database.user import User + +auth = Blueprint('auth', __name__) + + +@auth.route('/login', methods=['POST']) +def login(): + username = request.form.get('username') + password = request.form.get('password') + + user = User.query.filter_by(username=username).first() + if user and check_password_hash(user.password, password): + return {'id': user.id, + 'username': user.username, + 'email': user.email, + 'token': create_access_token(identity=user.username)} + return {'description': 'Username or password is invalid'}, HTTPStatus.UNAUTHORIZED + + +@auth.route('/signup', methods=['POST']) +def signup(): + username = request.form.get('username') + email = request.form.get('email') + password = request.form.get('password') + + user = User.query.filter_by(username=username).first() + if user: + return {'description': f'A user called {username} exists already.'}, HTTPStatus.CONFLICT + + # TODO sanity check for password length etc + user = User(username=username, + email=email, + password=generate_password_hash(password)) + db.session.add(user) + db.session.commit() + + return '', HTTPStatus.NO_CONTENT diff --git a/database/__init__.py b/database/__init__.py new file mode 100644 index 0000000..f0b13d6 --- /dev/null +++ b/database/__init__.py @@ -0,0 +1,3 @@ +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() diff --git a/database/user.py b/database/user.py new file mode 100644 index 0000000..1e9ba4a --- /dev/null +++ b/database/user.py @@ -0,0 +1,8 @@ +from . import db + + +class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String, unique=True) + email = db.Column(db.String, unique=True) + password = db.Column(db.String) diff --git a/main.py b/main.py index 564b91f..604cb05 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,19 @@ import random -import time from flask import Flask, request from flask_cors import CORS -# from flask_restful import Api +from flask_jwt_extended import JWTManager, jwt_required from flask_socketio import SocketIO +from database import db + app = Flask(__name__) cors = CORS(app) -# api = Api(app) sio = SocketIO(app, cors_allowed_origins='*') @app.route('/') +@jwt_required def home(): return {'url': '/', 'body': 'test body'} @@ -39,5 +40,14 @@ def public_message(kwargs): print(kwargs) sio.emit('public message', kwargs) + if __name__ == '__main__': + from auth.auth import auth as auth_blueprint + app.config['JWT_SECRET_KEY'] = 'super-secret-key' # TODO FIX THIS + app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite' + db.init_app(app) + JWTManager(app) + app.register_blueprint(auth_blueprint) + with app.app_context(): + db.create_all() sio.run(app, port=5005) diff --git a/requirements.txt b/requirements.txt index 9cff871..8d68396 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ eventlet==0.25.2 flask==1.1.2 flask-cors==3.0.8 -flask-restful==0.3.8 +flask-jwt-extended==3.24.1 flask-socketio==4.3.1 +flask-sqlalchemy==2.4.4 +Werkzeug~=1.0.1 \ No newline at end of file