2011-11-19 65 views
8

我想创建一个装饰为Flask路线标志某些航线为public,这样我就可以做这样的事情:创建瓶公共URL装饰

@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上下文功能。

我有点难住,因为我不知道如何获得public装饰器中给定函数的url规则。

也许这不是Flask的最佳设计选择,但我希望有另一个简单的&优雅的方式来实现这一点。

我以前见过这种模式,想模仿它。例如,这是Django的login_required修饰器的对应物。

我很喜欢读这方面的想法。

回答

5

烧瓶已经有一个login_required装饰器(见view decorators)。如果您使用public_urls来决定需要进行身份验证的网址,那么最好使用它。

+0

魔术!为此欢呼。 –

+1

糟糕 - 我只是意识到,尽可能接近我想要的,我不太确定这是我需要的答案。我有大约4个公共网站和100多个私人网站。我不想污染代码w /'@ login_required',所以我想有一个例如'before_request',否认所有的公共请求,除非在视图上有'@ public'。我希望你能明白为什么这不是答案,但你发布的内容绝对是一个很好的领先。如果我拿出答案,我会标记这个正确的,并发布我所做的。干杯。 –

1

最后我做这样的事情:

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