【问题标题】:Multi-User Restricted Access with Python EvePython Eve 的多用户限制访问
【发布时间】:2017-04-28 20:49:19
【问题描述】:

目前,Eve v0.4 通过“auth_field”支持用户受限资源访问,但它似乎旨在自动处理单一所有者的情况。

如果用户的 id 包含在允许的 id 数组中,您将如何启用多用户受限访问,即允许用户查看资源?可能有多个列表用于单独的读取和写入权限。

【问题讨论】:

    标签: eve


    【解决方案1】:

    我为 EVE 编写了一个小技巧,添加了这个功能。也许这有点棘手,但它确实有效。

    您需要为 EVE 更新 fdec 函数 auth.py:

    def fdec(f):
        @wraps(f)
        def decorated(*args, **kwargs):
            if args:
                # resource or item endpoint
                resource_name = args[0]
                resource = app.config['DOMAIN'][args[0]]
                if endpoint_class == 'resource':
                    public = resource['public_methods']
                    roles = resource['allowed_roles']
                    if request.method in ['GET', 'HEAD', 'OPTIONS']:
                        roles += resource['allowed_read_roles']
                    else:
                        roles += resource['allowed_write_roles']
                elif endpoint_class == 'item':
                    public = resource['public_item_methods']
                    roles = resource['allowed_item_roles']
                    if roles and isinstance(roles, str):
                        items = app.data.driver.db[args[0]]
                        item = items.find_one(kwargs)
                        roles = item[roles]
                    if request.method in ['GET', 'HEAD', 'OPTIONS']:
                        roles += resource['allowed_item_read_roles']
                    else:
                        roles += resource['allowed_item_write_roles']
                if callable(resource['authentication']):
                    auth = resource['authentication']()
                else:
                    auth = resource['authentication']
            else:
                # home
                resource_name = resource = None
                public = app.config['PUBLIC_METHODS'] + ['OPTIONS']
                roles = app.config['ALLOWED_ROLES']
                if request.method in ['GET', 'OPTIONS']:
                    roles += app.config['ALLOWED_READ_ROLES']
                else:
                    roles += app.config['ALLOWED_WRITE_ROLES']
                auth = app.auth
            if auth and request.method not in public:
                if not auth.authorized(roles, resource_name, request.method):
                    return auth.authenticate()
            return f(*args, **kwargs)
        return decorated
    return fdec
    

    如你所见,我添加了一个条件:if isinstance(roles, str) 这个想法是,当您将字符串放入 allowed_roles 而不是 list 时,这意味着您指向此项目中的一个字段,其中包含一个用户列表。因此,例如,我有下一个方案和组定义:

    definition = {
        'url': 'groups',
        'item_title': 'group',
        # only admins and apps are allowed to consume this endpoint
        'cache_control': '',
        'cache_expires': 0,
        'id_field': 'url',
        'schema': _schema,
        'allowed_item_roles': 'users',
        'additional_lookup': {
            'url': 'regex("[\w]+")',     # to be unique
            'field': 'url',
        },
    }
    
    _schema = {
        'name': required_string,  # group name
        'url': unique_string,       # group url - unique id
        'users': {                  # list of users, who registered for this group
            'type': 'list',
            'scheme': embedded_object('accounts')
        },
        'items': {                  # list of items in the group
            'type': 'list',
            'scheme': embedded_object('items'),
        },
        'owner': embedded_object('accounts'),
        'secret': {'type': 'string'}
    
    }
    

    如您所见,我有一个用户列表,它是我帐户的嵌入对象。下一步是更新角色身份验证。现在应该是这样的:

    def check_auth(self, token, allowed_roles, resource, method):
        accounts = app.data.driver.db['accounts']
        lookup = {'token': token}
        if allowed_roles:
            # only retrieve a user if his roles match ``allowed_roles``
            lookup['username'] = {'$in': allowed_roles}
        account = accounts.find_one(lookup)
        if account and 'username' in account:
            self.set_request_auth_value(account['username'])
        if account:
            self.request_auth_value = account['username']
        return account is not None
    

    所以它检查用户名是否在允许的角色中。最后一步是更新 EVE 中的 flaskapp.py 以支持 allowed_roles 中的字符串

    def validate_roles(self, directive, candidate, resource):
        """ Validates that user role directives are syntactically and formally
        adeguate.
    
        :param directive: either 'allowed_[read_|write_]roles' or
                          'allow_item_[read_|write_]roles'.
        :param candidate: the candidate setting to be validated.
        :param resource: name of the resource to which the candidate settings
                         refer to.
    
        .. versionadded:: 0.0.4
        """
        roles = candidate[directive]
        if not (isinstance(roles, list) or isinstance(roles, str)):
            raise ConfigException("'%s' must be list"
                                  "[%s]." % (directive, resource))
    

    无论如何,它仍然是一种解决方法,我不确定当每个项目有数千个用户时它是否会快速可靠地运行,但对于少量用户它可以工作。

    希望对你有帮助

    【讨论】:

    • 这是一个奇怪而令人敬畏的解决方案。如果我愿意这样做,我可能会将用户 ID 本身视为有效角色。并以某种方式添加allowed_read_roles_field,您是否以我应该知道的方式探索了那个前沿?
    【解决方案2】:

    用户受限资源访问本质上是一种机制,用于透明地存储创建文档的用户 ID 以及文档本身。当用户回到端点时,他只能看到/编辑他自己的文档。存储文档时如何为文档分配多个“所有者”?

    你看过Role Based Access Control吗?它可以满足您的要求,尽管是在端点(不是文档)级别。

    【讨论】:

    • 基于角色的访问控制不一样。这是端点上允许的角色的静态列表,而不是文档上允许的用户的动态列表。如果身份验证处理程序在做出身份验证决定之前接收到足够的信息来执行查找,那么它可以以类似的方式完成。但就目前而言,这不是解决方案。创建时有多个“所有者”是不必要的。我只是希望用户能够在创建对象后与其他用户共享对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 2017-02-08
    • 1970-01-01
    • 2019-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多