7

我一直在看这篇文章: http: //pythonhosted.org/Flask-Principal/#granular-resource-protection

现在虽然它当前的工作方式没有任何问题,但我看不出它非常有用,因为在登录时所有帖子都被读取并被EditBlogPostNeed添加到身份中。

想象一下,如果我写的帖子数量超过了正常数量,从长远来看,这将不是一个很好的策略,因为我想在访问视图时检查帖子/posts/<post_id>

有没有办法使用 对每个视图请求进行检查Flask Principal

我当然可以通过惰性关系查询和过滤器轻松解决它,但我想使用Flask Principal.

4

4 回答 4

1

不确定我是否完全理解您的问题,但这可能会有所帮助。在 Flask 应用程序中,我将 Flask-Principal 用于角色权限,例如管理员和编辑器,并且我还将它用于细粒度的资源保护,如Flask-Principal docs中所述。就我而言,我正在检查用户是否有权访问特定帐户。在每个视图中,都会加载身份并检查权限。

视图中:

@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)))
于 2014-07-15T02:15:31.390 回答
1

我能找到的关于这个话题的一切似乎都过于迟钝。虽然不是我最初想要的,但我决定在我的视图函数中简单地手动处理它。它更加明确,并且减少了对数据库的额外查询。请注意,我仍在使用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)
于 2018-09-13T22:53:28.343 回答
1

虽然 Flask-Principal 是最受欢迎的插件,但它并不复杂,而且在我需要的大多数情况下它不起作用。我一直试图强迫它以我喜欢的方式工作,但我从未成功过。幸运的是,我找到了一个非常简单且轻量级的模块——权限

用法

首先,您需要通过子类化定义自己的规则,Rule然后覆盖check()and 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.在视图代码中使用(usingwith语句)

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 %}
于 2015-12-18T13:42:15.547 回答
0

我的回答是基于您已经知道烧瓶主体如何工作以及它如何与数据库集成的假设。

首先,我们只需要在数据库中存储需求,如果您不知道为什么,我不建议您阅读下面我的答案

那么,回到你的问题,我们需要编辑一篇文章,如何进行粒度控制?

@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 并传入文章 id 和文章模型,然后我检查文章的 user_id 和烧瓶登录的 current_user.id

class MyPermission(Permission):
    pass


class MyIdentityContext():

    pass

如果用户是文章的作者,那么我返回True,用户可以编辑文章,如果不是,返回False,那么它可以工作。

--------我稍后会更新更多细节------------

于 2016-03-24T11:40:15.567 回答