Combine two python decorators into one

Here are two decorators that I would like to combine, since they are very similar, the difference is in how the non-authenticated user is handled. I would rather have one decorator that I can call with an argument.

# Authentication decorator for routes # Will redirect to the login page if not authenticated def requireAuthentication(fn): def decorator(**kwargs): # Is user logged on? if "user" in request.session: return fn(**kwargs) # No, redirect to login page else: redirect('/login?url={0}{1}'.format(request.path, ("?" + request.query_string if request.query_string else ''))) return decorator # Authentication decorator for routes # Will return an error message (in JSON) if not authenticated def requireAuthenticationJSON(fn): def decorator(**kwargs): # Is user logged on? if "user" in request.session: return fn(**kwargs) # No, return error else: return { "exception": "NotAuthorized", "error" : "You are not authorized, please log on" } return decorator 

And currently I use these decorators for certain routes, for example.

 @get('/day/') @helpers.requireAuthentication def day(): ... @get('/night/') @helpers.requireAuthenticationJSON def night(): ... 

I would prefer this:

 @get('/day/') @helpers.requireAuthentication() def day(): ... @get('/night/') @helpers.requireAuthentication(json = True) def night(): ... 

I am on python 3.3 using the Bottle framework. Can I do what I want? How?

+4
source share
2 answers

Just add another shell to capture the json parameter:

 def requireAuthentication(json=False): def decorator(fn): def wrapper(**kwargs): # Is user logged on? if "user" in request.session: return fn(**kwargs) # No, return error if json: return { "exception": "NotAuthorized", "error" : "You are not authorized, please log on" } redirect('/login?url={0}{1}'.format(request.path, ("?" + request.query_string if request.query_string else ''))) return wrapper return decorator 

I renamed your original requireAuthentication function to decorator (because this is what this function did, it decorated fn ) and renamed the old decorator to wrapper , the usual convention.

Regardless of what you put after @ , this is an expression that first evaluates the actual function of the decorator. @helpers.requireAuthentication() means you want to call requireAuthentication , and it returns as the actual decorator for the function to which the @ string applies.

+2
source

You can create a wrapper for both of these decorators:

 def requireAuthentication(json=False): if json: return helpers.requireAuthenticationJSON else: return helpers.requireAuthentication 

or

 import functools # Authentication decorator for routes # Will redirect to the login page if not authenticated def requireAuthentication(json=False): def requireAuthentication(fn): @functools.wraps(fn) def decorator(*args, **kwargs): # Is user logged on? if "user" in request.session: return fn(*args, **kwargs) if json: return { "exception": "NotAuthorized", "error" : "You are not authorized, please log on" } return redirect('/login?url={0}{1}'.format(request.path, ("?" + request.query_string if request.query_string else ''))) return decorator return requireAuthentication 
+1
source

Source: https://habr.com/ru/post/1486017/


All Articles