Колба Основной сыпучий ресурс по запросу
Я смотрел на этот пост: http://pythonhosted.org/Flask-Principal/
Теперь, несмотря на то, что нет ничего плохого в том, как это работает в настоящее время, я не вижу, что это очень удобно, так как во время входа в систему все сообщения читаются и EditBlogPostNeed
добавляется к личности.
Представьте, что если бы я писал больше обычного количества постов, это в долгосрочной перспективе не будет очень хорошей стратегией, так как я хотел бы проверить пост, когда получаю доступ к представлению. /posts/<post_id>
,
Есть ли способ сделать эту проверку на каждый запрос на просмотр с помощью Flask Principal
?
Конечно, я могу легко обойти это с помощью ленивых запросов и фильтров, но я хочу использовать Flask Principal
,
4 ответа
Не уверен, что полностью понимаю ваш вопрос, но это может помочь. В приложении Flask я использую Flask-Principal для разрешения роли, например, admin и editor, и также использую его для детальной защиты ресурсов, как описано в документации Flask-Principal. В моем случае я проверяю, есть ли у пользователя разрешение на доступ к определенной учетной записи. В каждом представлении загружается личность и проверяется разрешение.
По мнению:
@login_required
def call_list(id, page=1):
dept = models.Department.query.get_or_404(id)
view_permission = auth.ViewAccountPermission(dept.office.account_id)
if view_permission.can():
# do something
Пользовательское разрешение:
ViewAccount = namedtuple('View', ['method', 'value'])
ViewAccountNeed = partial(ViewAccount, 'view')
class ViewAccountPermission(Permission):
def __init__(self, account_id):
need = ViewAccountNeed(unicode(account_id))
super(ViewAccountPermission, self).__init__(need)
А в функции загрузки идентификаторов:
if hasattr(current_user, 'assigned_accounts'):
for account_id in current_user.assigned_accounts():
identity.provides.add(auth.ViewAccountNeed(unicode(account_id)))
Все, что я могу найти в этой теме, кажется слишком тупым. Хотя это и не то, что я изначально хотел, я решил просто обработать это вручную в своих функциях просмотра. Это более явно, и это уменьшает дополнительные запросы к базе данных. Обратите внимание, что я все еще использую flask-security
для его встроенной аутентификации на основе ролей (которая все еще реализуется через flask-principal
через его @roles_accepted('role')
декоратор.
@app.route('/my_accounts/', methods = ['GET'])
@app.route('/my_accounts/<int:id>/', methods = ['GET'])
@roles_accepted('client')
def my_accounts(id=None):
if id:
account = Account.query.get_or_404(id)
if account.owner == current_user:
return render_template("my_account.html",
title = "Account: {0}".format(account.name),
account = account)
else:
abort(403)
accounts = Account.query.filter_by(owner=current_user).all()
return render_template("my_accounts.html",
title = 'My Accounts',
accounts = accounts)
Хотя Flask-Principal является самым популярным плагином, он не является сложным и не работает в большинстве случаев, когда он мне нужен. Я пытался заставить его работать так, как мне нравится, но мне это никогда не удавалось. К счастью, я нашел чрезвычайно простой и легкий модуль - разрешение:
использование
Во-первых, вам нужно определить свои собственные правила с помощью подклассов Rule
затем переопределить check()
а также deny()
:
# rules.py
from flask import session, flash, redirect, url_for
from permission import Rule
class UserRule(Rule):
def check(self):
"""Check if there is a user signed in."""
return 'user_id' in session
def deny(self):
"""When no user signed in, redirect to signin page."""
flash('Sign in first.')
return redirect(url_for('signin'))
Затем вы определяете разрешения путем создания подклассов Permission
и переопределить rule()
:
# permissions.py
from permission import Permission
from .rules import UserRule
class UserPermission(Permission):
"""Only signin user has this permission."""
def rule(self):
return UserRule()
Есть 4 способа использования UserPermission
определено выше:
1. Используйте в качестве декоратора представления
from .permissions import UserPermission
@app.route('/settings')
@UserPermission()
def settings():
"""User settings page, only accessable for sign-in user."""
return render_template('settings.html')
2. Используйте в кодах представления
from .permissions import UserPermission
@app.route('/settions')
def settings():
permission = UserPermission()
if not permission.check()
return permission.deny()
return render_template('settings.html')
3. Используйте в представлении коды (используя with
заявление)
from .permissions import UserPermission
@app.route('/settions')
def settings():
with UserPermission():
return render_template('settings.html')
4. Используйте в шаблонах Jinja2
Сначала вам нужно добавить определенные вами права доступа к контексту шаблона:
from . import permissions
@app.context_processor
def inject_vars():
return dict(
permissions=permissions
)
тогда в шаблонах:
{% if permissions.UserPermission().check() %}
<a href="{{ url_for('new') }}">New</a>
{% endif %}
Мой ответ основан на предположении, что вы уже знаете, как работает принципал фляги и как он интегрируется с базой данных.
Во-первых, нам нужно хранить только потребности в базе данных, если вы не знаете, почему, я не рекомендую вам прочитать мой ответ ниже
Тогда, вернемся к вашему вопросу: нам нужно отредактировать статью, как это контролировать?
@app.route('/article/edit/<id>'):
@Permission(Need('edit', 'article')).require()
def article(id):
pass
Личность пользователя
id = identity(user.id)
id.provide.add(Need('edit','article'))
Тогда у пользователя есть разрешение на редактирование статьи.@Permission(Need('edit', 'article')).require()
вернет true для каждой статьи, даже если пользователь не является автором статьи. Это ваша проблема, верно?
Ниже показано, как я решаю эту проблему
поскольку Permission.require() по умолчанию не предоставляет никаких аргументов для передачи, поэтому я определяю свои Permisson и IdentityContext и передаю идентификатор статьи и модель статьи, затем я проверяю user_id статьи с помощью current_user.id в флеш-логине.
class MyPermission(Permission):
pass
class MyIdentityContext():
pass
Если пользователь является автором статьи, тогда я возвращаю True, пользователь может редактировать статью, если нет, возвращает False, тогда это работает.
-------- Я обновлю более подробно позже ------------