2011-11-19 63 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"))