3

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?

Luke
  • 1,794
  • 10
  • 43
  • 70

0 Answers0