Создайте декоратор публичной ссылки Flask - PullRequest
8 голосов
/ 19 ноября 2011

Я бы хотел создать декоратор для Flask маршрутов, чтобы пометить определенные маршруты как общедоступные, чтобы я мог делать такие вещи:

@public
@app.route('/welcome')
def welcome():
    return render_template('/welcome.html')

В другом месте, вот что я былдумая, что декоратор и проверка будут выглядеть так:

_public_urls = set()

def public(route_function):
    # add route_function's url to _public_urls
    # _public_urls.add(route_function ...?.url_rule)
    def decorator(f):
        return f

def requested_url_is_public():
    from flask import request
    return request.url_rule in _public_urls

Затем, когда запрос сделан, у меня есть контекстная функция, которая проверяет requested_url_is_public.

Я немного озадачен, потому что яне знаю, как получить правило url для данной функции в декораторе public.

Возможно, это не лучший выбор дизайна для Flask, но я ожидаю, что есть еще один простой и элегантный способдля достижения этой цели.

Я видел подобные шаблоны раньше и хотел бы имитировать их.Например, это что-то вроде аналога декоратора login_required Джанго.

Я бы с удовольствием прочитал мысли по этому поводу.

Ответы [ 2 ]

5 голосов
/ 19 ноября 2011

Flask уже имеет login_required декоратор (см. просмотр декораторов ). Если вы используете public_urls, чтобы решить, для каких URL требуется аутентификация, вам, скорее всего, лучше использовать это.

1 голос
/ 20 ноября 2013

Я закончил тем, что делал что-то вроде этого:

def public(endpoint):
    """A decorator for endpoints that flags them as publicly accessible

    The endpoint is the Flask endpoint function. This is later tested by the
    _is_public function, which is called before every request.

    Note that @public must come AFTER route.add i.e.
    @app.route('...')
    @public
    def handler(): ...
    """
    @wraps(endpoint)
    def public_endpoint(*args, **kwargs):
        return endpoint(*args, **kwargs)
    public_endpoint._is_public = True
    return public_endpoint

и

def _is_public(endpoint):
    """Return true if the given endpoint function is public

    Tests whether the @public decorator has been applied to the url.
    """
    return getattr(endpoint, '_is_public', False) is True


@blueprint.before_app_request  # or @app.before_request
def security_check():
    """Check all incoming requests for a current user.
    """  
    if current_user.is_logged_in:  # need current_user test elsewhere
        # we don't need to check if we have a public url if the user is
        # logged in
        return

    try:
        if _is_public(current_app.view_functions[request.endpoint]):
            # we just go perform the endpoint function if it is public
            return
    except KeyError:
        # There is no endpoint matching the request
        abort(404)

    # user is not logged in and it's not a public url
    logging.info("No current user and %s is not public" % request.path[1:])

    # send the user to the welcome page
    return redirect(url_for("some_public_page"))
...