用户依赖的资源过滤器在Python-eve RestApi框架中

2 投票
5 回答
1345 浏览
提问于 2025-04-17 21:25

我想在Python的Eve框架中实现一个“更复杂”的过滤器,这个过滤器是基于用户的访问权限来工作的。

问题

我们使用的是令牌认证,用户账户是在TokenAuth类中获取的。每个用户都有一些合同,每个合同下又有账单。我想实现一个接口/bills,能够显示用户合同下的账单。我们使用的是mongodb数据库。

为了更好地理解,可以想象成这样的SQL语句:"SELECT * FROM bills WHERE bills.contract IN user.contracts"

user { contracts : ["a","b","c"] }
bills { contract: "a" }

背景信息

class TokenAuth(TokenAuthBase):
    def check_auth(self, token, allowed_roles, resource, method):
       users = app.data.driver.db['users']
       TokenAuth.account = users.find_one(lookup)
       ...

(更新)

用户限制资源访问(URRA)

用户 1 : 多个账单的情况下,URRA可以解决这个问题。可以查看Python Eve文档中的URRA

在更复杂的情况下,需要编写一个自定义的过滤查询。我需要这个选项 :)。

更新

我找到了解决方案,见更新的回答。

5 个回答

0

下面是一个更完整的例子,假设我们在settings.py文件中有以下内容:

note_schema = {
    'user_id': {
        'type': 'objectid',
        'required': True,
        'readonly': True
    }
}
user_schema = {
    'username': {
        'type': 'string',
        'required': True,
        'unique': True,
    },
    'password': {
        'type': 'string',
        'required': True,
    },
    'token': {
        'type': 'string',
        'required': True,
    }
}

DOMAIN = {
    'user': {
        'schema': user_schema,
    },
    'note': {
        'schema': note_schema,
    },
}

然后,身份验证(auth)会根据用户名添加一个过滤器,这个过滤器的逻辑很简单,但你可以根据需要在过滤器中添加任何内容。

class MyAuth(BasicAuth):
    def check_auth(self, token, allowed_roles, resource, method):
        username = get_username_from_token(token)
        if resource == 'note':
            note = app.config['DOMAIN']['note']
            user = app.data.driver.db['user'].find_one({'username': username})
            note['datasource']['filter'] = {'user_id': user['_id']}

        return True
0

你有没有查看过 用户限制资源访问 的内容?

简单看一下,我觉得可以把用户的令牌(或者用户的ID,或者在你系统中用来识别用户的其他东西)存储在账单文件中,然后在 bills 这个接口上启用用户限制资源访问,这样就可以实现了。

1

我觉得最好是按每个请求来处理这个问题。修改 'DOMAIN' 可能会导致多个用户同时登录并发送请求的情况,这样在请求之间,域名可能会根据你实现的方式而变化。也许像下面这样的方法会有效:

from eve import Eve
from eve.auth import BasicAuth

def pre_get_api_stuff(resource, request, lookup):
    username = request.authorization['username']
    accounts = app.data.driver.db['accounts']
    account = accounts.find_one({'username': username})
    if resource == 'notes':
        lookup.update({'username': username})

app = Eve(auth=BasicAuth)
app.on_pre_GET += pre_get_api_stuff
2

那预定义的数据库过滤器呢?

bills = {
    'datasource': {
        'source': 'bills',
        'filter': {'field1': 'value1', 'field2': 'value2'}
    }
}

source 是一个mongodb的集合;filter 是一个mongodb的查询。这个过滤器会在任何请求到达接口之前自动应用(在客户端查询之前)。

2

感谢Nicola Iaorcci,我找到了一个解决办法。

首先,我为每个接口使用了一个自定义的认证类。

class MyCreditNoteAuth(TokenAuthBase):
   def check_auth(self, token, allowed_roles, resource, method):
        account = app.data.driver.db['users'].find_one({'api_access_token': token})

这个方法从mongodb中获取用户的账户信息,现在我可以访问他的合同ID了。

其次,在上面的方法中,我在每次请求时更新数据源的过滤条件:

mynotes['datasource']['filter']['contract'] = { '$in': account['contracts'] }

现在客户在这个接口上只看到自己的“笔记”。

撰写回答