Скрытие недоступных ссылок в шаблонах Jinja2

Мы пишем веб-приложение в Flask + Jinja2 на работе. Приложение зарегистрировало пользователей, которые могут получить доступ к определенным страницам в зависимости от их ролей. Чтобы добиться этого на стороне сервера, мы просто используем оформление страниц:

@app.route('/action1') @security_requirements(roles=['some_role']) def action1(): ... 

Декоратор проверяет, имеет ли зарегистрированный пользователь «some_role» в своем списке ролей и решает, передавать ли вызов украшенной функции или просто перенаправить пользователя на страницу «отказано в доступе».

Приложение также имеет панель навигации, реализованную с использованием бутстрапа. Панель навигации отображается на каждой странице с использованием базового шаблона. На данный момент каждая страница приложения имеет запись в панели навигации, независимо от того, может ли текущий пользователь получить к ней доступ или нет. Несмотря на то, что это не ядро ​​безопасности, я хотел бы скрыть страницы пользователей, к которым они не могут получить доступ. Кроме того, я хотел бы достичь этой функциональности, не дублируя списки разрешенных ролей внутри шаблонов Jinja. Возможно ли реализовать эту функциональность в Jinja каким-то образом, используя мой текущий декоратор?

2 Solutions collect form web for “Скрытие недоступных ссылок в шаблонах Jinja2”

Я использую Flask-Security , который связывает большое количество модулей входа / безопасности вместе в приятном пакете. Он поставляется с поддержкой управления ролью Flask-Principal, что позволит вам делать:

 {% if current_user.has_role('admin') %} <li><a href="#">Manage Site</a></li> {% endif %} 

Вы можете видеть, как это реализовано в источнике , прокси current_user поступает из Flask-Login

Я изменил декоратор security_requirements чтобы он выглядел так:

 def security_requirements(logged_in=True, roles=None): def wrapper(f): # Store the security attributes as a member of the function object f.access_control = dict(logged_in=logged_in, roles=roles) @functools.wraps(f) def wrapped(*args, **kwargs): access_result = _eval_access(logged_in, roles) # Redirect the user to the appropriate page (Access denied / Login Required / Actual Page) based on the result ... 

Единственное реальное отличие от предыдущей версии этого декоратора – это строка, в которой хранятся атрибуты безопасности внутри объекта функции. Эта линия бесполезна внутри декоратора. Однако теперь я могу реализовать следующее действие для вызова из шаблона Jinja:

 {% if can_access(func) %} <li><a>...</a></li> {% endif %} 

Функция can_access определена в прикладном модуле Flask. Он получает строку, которую он должен преобразовать в объект функции. Он делает это, вызывая app.view_functions :

 def can_access(func): return auth.can_access(app.view_functions[func]) 

Эта функция должна вызываться непосредственно из шаблона Jinja. Поэтому его необходимо добавить к глобальным переменным Jinja:

 app.jinja_env.globals.update(can_access=can_access) 

Наконец, auth.can_access :

 def can_access(f): if not hasattr(f, 'access_control'): return True # Use the access_control member set by the decorator return _eval_access(**f.access_control) == AccessResult.ALLOWED 

Это решение означает, что управление доступом определено в одном месте – которое является декоратором функции.

Python - лучший язык программирования в мире.