I wrote a function based decorator to handle the authentication to my company web services:
def company_auth(path=None, method=None):
"""
Company Webservices authentication decorator
:param path: relative url of the endpoint;
:param method: http method used for the call
usage example:
@company_auth(path='/api/MO/GetDetails', method='GET')
def mo_get_details(**kwargs):
path = kwargs.pop('path')
headers = kwargs.pop('headers')
...
retrieve a valid token, compute the signature and pass to the inner function
the headers dict and the path parameter as kw arguments.
"""
def _signature_wrapper(fn, path, method):
def wrapper(*args, **kwargs):
token = get_valid_token()
signature_dict = {
'url': path,
'token': token.token,
'secret': token.secret,
'method': method
}
make_signature_results = make_signature(**signature_dict)
headers = {
'comp-header-date': make_signature_results['date'],
'comp-header-session-token': signature_dict['token'],
'comp-header-signature': make_signature_results['signature'],
'Content-Type': CONTENT_TYPE,
}
kwargs['headers'] = headers
kwargs['path'] = path
results = fn(*args, **kwargs)
return results
return wrapper
def decorating_fn(fn):
wrapper = _signature_wrapper(fn, path, method)
return update_wrapper(wrapper, fn)
return decorating_fn
def get_valid_token():
"""
get a valid token from db or generate a new one from company webservices.
"""
if not APIToken.objects.exists(): # this is a Django model
return set_new_token()
api_token = APIToken.objects.first()
if not api_token.is_valid:
return set_new_token()
else:
return api_token
It works fine, although I save the generated values of token/secret on database through the Django ORM. I’d like to avoid this, turning it into a Class based decorator, instantiating it as a singleton and importing it in different modules. I’d like to keep the value of the token/secret pair not on database but in memory (as attributes of that instance), something like:
# Wanted CB Decorator
def CompanyAuth():
"""
Class Based Company Webservices authentication decorator
"""
def __init__(self, *args, **kwargs):
...
def __get__(self, *args, **kwargs):
...
def __call__(self, *args, **kwargs):
...
comp_auth = CompanyAuth()
# the singleton can then be imported by other modules and used
Is it doable and how I can achieve this?