Search code examples
pythonrestjwttokenfalconframework

How to create user authentication with tokens for multiple user levels with a python falcon rest api


I have created a rest api using python falcon api. It's to access the prediction values of a particular bank atm and read, update, delete values.

import falcon
import MySQLdb
import json


import re
import mysql.connector
from mysql.connector import  Error

class TesResource:

def on_get(self, req, resp):

    try:
        atmid=req.get_param('atm_key_id')
        datestart=req.get_param('prediction_date_start')
        dateend=req.get_param('prediction_date_end')

        if atmid is None or atmid=="" or datestart is None or dateend is None:
            resp.body=json.dumps({'error': 'Parameter is invalid'})
            resp.status=falcon.HTTP_500
            return resp

        conn = mysql.connector.connect(host='localhost', database='bank', user='root', password='', autocommit=True)
        if conn.is_connected():
            print('connected')

        cursor=conn.cursor()

        #q="SELECT prediction_amount FROM prediction WHERE atm_key_id=5 AND (prediction_date BETWEEN '2017-10-01' AND '2017-10-1')"
        q="SELECT prediction_amount FROM prediction WHERE atm_key_id=%s AND (prediction_date BETWEEN %s AND %s)" 
        #q=("SELECT * FROM prediction")
        cursor.execute(q,(atmid, datestart, dateend,))
        rows=cursor.fetchall()

        output={'tes':[]}
        for row in rows:

            #data={"key":row[0], "amount":float(row[2])}
            data={"amount":float(row[0])}
            output['tes'].append(data)

        resp.status=falcon.HTTP_200
        resp.body=json.dumps(output, encoding='utf-8')
        cursor.close()
        conn.close()

    except Exception as e:
        resp.body=json.dumps({'error':str(e)})
        resp.status=falcon.HTTP_500
        return resp

def on_put(self, req, resp):

    try:


        atmid=req.get_param('atm_key_id')
        date=req.get_param('prediction_date')
        amount=req.get_param('prediction_amount')
        if atmid is None or atmid=="" or date is None or amount is None:
            resp.body=json.dumps({'error': 'Parameter is invalid'})
            resp.status=falcon.HTTP_500
            return resp

        conn = mysql.connector.connect(host='localhost', database='bank', user='root', password='', autocommit=True)
        if conn.is_connected():
            print('connected')

        cursor=conn.cursor()

        q="""UPDATE `prediction` SET `prediction_amount`=%s WHERE atm_key_id=%s AND prediction_date=%s """
        cursor.execute(q,(amount, atmid, date,))
        conn.commit()
        cursor.close()

        output={'status':"Data successfully updated"}

        resp.status=falcon.HTTP_200
        data_resp=json.dumps(output, encoding='utf-8')
        resp.body=data_resp


    except Exception as e:
        conn.rollback()
        resp.body=json.dumps({'error':str(e)})
        resp.status=falcon.HTTP_500
        return resp


def on_delete(self, req, resp):

    try:
        atmid=req.get_param('atm_key_id')
        date=req.get_param('prediction_date')
        if atmid is None or atmid=="" or date is None:
            resp.body=json.dumps({'error': 'Parameter is invalid'})
            resp.status=falcon.HTTP_500
            return resp

        conn = mysql.connector.connect(host='localhost', database='bank', user='root', password='', autocommit=True)
        if conn.is_connected():
            print('connected')

        cursor=conn.cursor()

        q="""DELETE FROM `prediction` WHERE atm_key_id=%s AND prediction_date=%s"""

        cursor.execute(q, (atmid, date,))
        conn.commit()
        cursor.close()

        output={'status':"Data successfully deleted"}

        resp.status=falcon.HTTP_200
        data_resp=json.dumps(output, encoding='utf-8')
        resp.body=data_resp

    except Exception as e:

        conn.rollback()
        resp.body=json.dumps({'error':str(e)})
        resp.status=falcon.HTTP_500
        return resp

There are two user levels. Everyone can get the prediction value for a particular date or date range(access level 1). But only authorized set of people can update or delete a prediction value(access level 2). I have a user mysql table. It has username, userid and access_level(1 or 2) as columns. How can I create a user authentication using tokens? Any insight will be really helpful.


Solution

  • You could use middleware, and check paths and tokens and other params there, before the request is processed. It is the cleanest way as you can add several middlewares, for each level, and let the resources clean and separated from this privilege level logic.

    Have a look to the AuthMiddleware example, you can analyse the request and raise unauthorized exception HTTP_401. Be consistent with HTTP standard.

    To add several middlewares you can use the falcon API constructor.

    app = falcon.API(middleware=[
        AuthMiddleware(),
        UserPrivilegeMiddleware()
    ])