2011-11-19 17 views
8

Me gustaría crear un decorador para Flask rutas para marcar ciertas rutas como público, por lo que puedo hacer cosas como esta:Crear un decorador Frasco URL pública

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

En otros lugares, aquí es lo que estaba pensando lo decorador y verificación se vería así:

_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 

Luego, cuando se realiza una solicitud, que tienen una función que comprueba contexto requested_url_is_public.

Estoy un poco perplejo porque no sé cómo obtener la regla url para una función dada en el decorador public.

Quizás esta no sea la mejor opción de diseño para Flask, pero espero que exista otra manera sencilla de lograrlo &.

He visto estos patrones como este antes, y me gustaría imitarlo. Por ejemplo, esto es una contraparte del decorador login_required de Django.

Me gustaría leer pensamientos sobre esto.

Respuesta

5

Frasco ya tiene un decorador login_required (ver view decorators). Si está utilizando public_urls para decidir para qué URLs se debe autenticar, lo más probable es que esté mejor utilizando eso.

+0

magia! Saludos por esto. –

+1

Vaya, me acabo de dar cuenta de que, tan cerca como sea de lo que quiero, no estoy muy seguro de que sea la respuesta que necesito. Tengo alrededor de 4 URL públicas y más de 100 privadas. No quiero contaminar el código w/'@ login_required', así que me gustaría tener un ejemplo' before_request' que niegue todas las solicitudes públicas a menos que exista un '@ public' en la vista. Espero que puedan ver por qué esta no es exactamente la respuesta, pero lo que han publicado definitivamente es una gran ventaja. Si se me ocurre la respuesta, marcaré esto como correcto y publicaré lo que hice. Aclamaciones. –

1

que terminé haciendo algo como esto:

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 

y

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")) 
Cuestiones relacionadas