Search code examples
pythonpython-3.xflaskpython-decorators

Problems with the creation of a authentication decorator for Flask


I'm trying to set up an authentication decorator for all my Flask app.routes. Every time a function associated with a route is called I check if the correct key was passed with the request.

I've created a decorator (which is probably wrong) to do that. First it said that it didn't had a configured a return value, which I later fixed. When i tried to run it again the error said:

"TypeError: unregisterApi() takes 0 positional arguments but 2 were given The view function did not return a valid response. The return type must be a string, tuple, Response instance, or WSGI callable, but it was a function. ".

I'm certain that the problem is my decorator, but I have no idea how to fix it.

Here's the code for the decorator and the decorated function:

Decorator:

def requestAuth(func):
   def funcWrapper():
       data = request.get_json(force=True)
       apiAddr = request.remote_addr
       apiKey = data["API Register Key"]

       conn = sqlite3.connect("database/controllerConfiguration.db")
       cursor = conn.cursor()
       cursor.execute('select apikey from SystemAPI where apihost  = \"{0}\";'.format(apiAddr))
       result = cursor.fetchall()
       if result[0][0] != apiKey:
           return "ERROR - Authentication with the controller failed",400
       elif result[0][0] == apiKey:
           return func
   return funcWrapper

Route associated function that it decorates:

@app.route('/unregister',methods=['POST'])
@requestAuth
def unregisterApi():
   data = request.get_json(force=True)
   apiKey = data["API Register Key"]
   apiAddr = request.remote_addr

   conn = sqlite3.connect('database/controllerConfiguration.db')
   cursor = conn.cursor()
   cursor.execute('delete from SystemAPI where apikey = \"{}\";'.format(apiKey))
   conn.commit()
   conn.close()

   return jsonify({"Response":"Success"})

What i was hoping to achive was:

Every time a route (/unregister,/register,...) function was called the @requestAuth decorator would check if the correct Key was passed, if it was it would resume to the route function and execute what it should, if the key didn't match it would simply return and error string with the associated status code (string: "ERROR - Authentication with the controller failed", Status code: 400).


Solution

  • The problem is with the elif statement in funcWrapper:

    elif result[0][0] == apiKey:
       return func
    

    func is a callable object i.e the original function wrapped by requestAuth, which, in this case, is unregisterApi. Instead, call func to return the valid type rather than the object instance itself:

    elif result[0][0] == apiKey:
       return func()
    

    Also, bear in mind that if both the if and elif statements fail, None will be returned by funcWrapper, raising the original error again. Thus, you may want to reconsider how you wish to handle that particular case.