Колба Основной сыпучий ресурс по запросу

Я смотрел на этот пост: 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, тогда это работает.

-------- Я обновлю более подробно позже ------------

Другие вопросы по тегам