python - what's the correct way to find out flask's endpoint by function name? -


i have flask demo, , needs access control. access control base on function name, , wrote decorator it.

the decorator define is:

def permission(fn):     @wraps(fn)     def wraped(*args, **kwargs):         if _do_validate(fn.__name__):  # todo check user has privileges here             return fn(*args, **kwargs)         else:             abort(401)     return wraped 

usage example follow:

    @app.route('/index')     @permission     def index():         return 'hello world' 

this work fine if user don't specify endpoint, because flask's default endpoint fn.__name__, in example endpoint='index'.

but when user specify endpoint, or use blueprint, endpoint changed. example:

    bl = blueprint('admin', __name__)      @bl.route('hello')     @permission     def hello():         return 'hello world in blueprint' 

the endpoint changed admin.hello.

i don't want specify arg in @permission, write new permission decorator follow:

def permission(fn):     @wraps(fn)     def wraped(*args, **kwargs):         m = fn.__module__.split('.')         if len(m) <= 2:             # app must define in root module, if user not use blueprint, juse use fn.__name__ endpoint             reg_f = fn.__name__         else:             # blue print must define in submodule             reg_f = '{0}.{1}'.format(m[1], fn.__name__)          if _do_validate(ref_f):  # todo check user has privileges here             return fn(*args, **kwargs)         else:             abort(401)     return wraped 

the problem solved, think it's not elegant.

can give me better one? thx.

your solution not valid in case of blueprint's name not equal module's __name__.

i can propose next solution:

from collections import defaultdict registered = defaultdict(int)  def permission(fn):     registered[fn.__name__] += 1     fn.permission_token = "%s.%s" % (fn.__name__, registered[fn.__name__])      @wraps(fn)     def wraped(*args, **kwargs):         if _do_validate(fn.permission_token):             return fn(*args, **kwargs)         else:             abort(401)     return wraped  @permission def foo():     pass  @permission def bar():     pass  def _do_validate(permission_token):     return {foo.permission_token: true,             bar.permission_token: false}.get(permission_token, false) 

the main drawback of have import routes in _do_validate's module create such "access control list".

upd: ok, because of want use endpoint values check user access, next solution allows find endpoint view function:

from collections import defaultdict flask import current_app  def find_endpoint(fn):     # loop can optimized maintaining     # {permission_token => endpoint} dict.     endpoint, view_func in current_app.view_functions.items():         if getattr(view_func, 'permission_token', none) == fn.permission_token:             return endpoint     return none  registered = defaultdict(int)  def permission(fn):     registered[fn.__name__] += 1      @wraps(fn)     def wrapped(*args, **kwargs):         endpoint = find_endpoint(wrapped)         assert endpoint not none         if _do_validate(endpoint):             return fn(*args, **kwargs)         else:             abort(401)      # work because flask's route decorator returns     # original view function, not wrapped one.     wrapped.permission_token = "%s.%s" % (fn.__name__, registered[fn.__name__])     return wrapped  def _do_validate(endpoint):     # or search in db     return {'index': true,             'bp.index': false}.get(endpoint, false) 

however, checking access endpoint not idea, because code change during development process lead undesired losing (or worse - retrieving!) access. so, opinion using action (or resource) argument permission decorator reasonable. such parameter can freely modify endpoints/view functions without undesired side effects.

upd2: actually, more simple way find endpoint value wrapper function use request.endpoint.


Comments

Popular posts from this blog

how to insert data php javascript mysql with multiple array session 2 -

multithreading - Exception in Application constructor -

windows - CertCreateCertificateContext returns CRYPT_E_ASN1_BADTAG / 8009310b -