Dubai Silicon Oasis, Dubai, UAE

Flask Authentication

A Flask API with Authentication and Credit Management

There is a ton of sample codes out there on StackOverflow or GitHub that help to create Flask API and allow authentication for this API.

I’m not very good in embedding part of the code in a post, so I will just leave the code here and the post to be edited later.

In this post, I will cover a way to create the Flask API, allow authentication on this API with username and token saved in MySQL Database.

I will also show how I managed to control the registered users’ credit so that each user has a credit score to use the API. This credit can be reset each month through a separate function not showing in the sample code.

I will also show in the code how to add and remove a background task and set a run time for it.

The sample code can be found on GitHub: https://github.com/MohdElBasyouni/flask_authentication

from flask import Flask, jsonify, abort, request, Response
from flask_login import LoginManager, UserMixin, login_required
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
import mysql.connector
import json
import os
import signal
import logging
import datetime
sched = BackgroundScheduler()
# I'm disabling Logging as other parts of the code need to have clear log without too much of nothing to do logs
logging.getLogger('apscheduler.scheduler').propagate = False
def job():
print('Hello')
# The ID here is mandatory to remove this function from Background once needed
sched.add_job(job, 'interval', seconds=10, id='main')
# Flask def
app = Flask(__name__)
# app.config['ENV'] = 'development'
app.config['ENV'] = 'deployment'
# app.config['DEBUG'] = True
# app.config['TESTING'] = True
app.secret_key = 'KEYSECRET' # Change this!
login_manager = LoginManager()
login_manager.init_app(app)
def sendMail(subject, body, attach, email):
subject = 'LOCAL - ' + subject
if email == None:
to = 'product_owner_mail@mail.com'
else:
to = email
yag = yagmail.SMTP("scrum_mail@mail.com", 'password')
yag.send(
to=to,
subject= subject,
contents=body,
attachments=attach,
)
def db_check():
mydb = mysql.connector.connect(host="localhost",user="Manager",password="ManagerPWD",database = "DBNAME")
mycursor = mydb.cursor(dictionary=True)
mycursor.execute('SELECT USERNAME, TOKEN, CREDIT FROM USERS')
rows = mycursor.fetchall()
newdata = [{dic['USERNAME']: (dic['TOKEN'], dic['CREDIT'])} for dic in rows]
diction_user_token = {}
for item in newdata:
for key, value in item.items():
diction_user_token[key] = value
user_database = diction_user_token
return user_database
class User(UserMixin):
# Load your users from DB here if you wish to have an instant from it, otherwise put in the get function below
# user_database = db_check()
# Sample of the returned data
# user_database = {"melbasyouni": ("p50Bux2fe1JCLkkkVYqt6r,G", 10000000),"JaneDoe": ("Jane", 10000000)}
def __init__(self, username, password):
self.id = username
self.password = password
@classmethod
def get(cls,id):
user_database = db_check()
# Sample of the returned data
# user_database = {"melbasyouni": ("p50Bux2fe1JCLkkkVYqt6r,G", 10000000),"JaneDoe": ("Jane", 10000000)}
return user_database.get(id)
@login_manager.request_loader
# API Request should have ?token=username:password at the end of the URL
def load_user(request):
global credit_score
token = request.headers.get('Authorization')
if token is None:
token = request.args.get('token')
if token is not None:
username,password = token.split(":")
user_entry = User.get(username)
if (user_entry is not None):
user = User(username,user_entry)
if (user.password[0] == password):
# Check if user has credit and update global variable
if (user.password[1] > 0):
new_value = user.password[1] - 1
credit_score = True
# Update the Database with the new credit for this user
sql_queries.users_credit_update_API(user.password[0], new_value)
return user
else:
credit_score = False
return user
return None
@login_manager.unauthorized_handler
def unauthorized_callback():
return (jsonify({'Status': 'Access Not Authorized'}), 201)
@app.before_request
def before():
print("This is executed BEFORE each request.")
@app.route('/_ah/warmup')
def warmup():
# Handle your warmup logic here, e.g. set up a database connection pool
return '', 200, {}
@app.route('/api/v1.0/banks_data/<bank>/', methods = ['GET'])
@login_required
def banks_data(bank):
# Check if user has credit
if credit_score == True:
if bank != None:
# Return the needed Data
return (jsonify({'Data': 'Hope you get the data'}), 201)
else:
return (jsonify({'Status': 'Requested Bank Code can not be None'}), 201)
# Check if user has credit failed
else:
return (jsonify({'Status': 'No enough credit for this account'}), 201)
@app.route('/stopServer', methods=['GET'])
@login_required
def stopServer():
try:
logging.info("Stopping Flask API")
subject = 'Flask API Logic Stopped'
body = 'Flask API Logic Stopped with embedded functions.'
# Remove Background Function before stopping the Flask API
if sched is not None:
sched.remove_job('main')
# Good Idea to send Mail in case API stopped
sendMail(subject, body, None, None)
os.kill(os.getpid(), signal.SIGINT)
return jsonify({ "success": True, "message": "Server is Stopping..." })
except Exception as err:
logging.info("Something went wrong with Flask API, error is '" + str(err) + "'")
subject = 'Flask API Logic Stopping Failed'
body = "Something went wrong with Flask API, error is '" + str(err) + "'"
# Good Idea to send Mail in case API failed to stop
sendMail(subject, body, None, None)
return (jsonify({'Status': 'Something went wrong when stopping server'}), 201)
if __name__ == '__main__':
try:
sched.start()
app.run(host='0.0.0.0', port=5000)
# In case SSL is needed, an adhoc ssl context can be added as a parameter to the app.run
# ssl_context='adhoc'
except Exception as err:
logging.info("Something went wrong with Flask API, error is '" + str(err) + "'")
subject = 'Flask API Logic Failed'
body = "Something went wrong with Flask API, error is '" + str(err) + "'"
# It's a good idea to send Mail in case the App Failed to run => A Cloud Practice I'm using
sendMail(subject, body, None, None)
view raw flask_auth.py hosted with ❤ by GitHub
0
Privacy Preferences
When you visit our website, it may store information through your browser from specific services, usually in form of cookies. Here you can change your privacy preferences. Please note that blocking some types of cookies may impact your experience on our website and the services we offer.