用户依赖的资源过滤器在Python-eve RestApi框架中
我想在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 个回答
下面是一个更完整的例子,假设我们在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
你有没有查看过 用户限制资源访问 的内容?
简单看一下,我觉得可以把用户的令牌(或者用户的ID,或者在你系统中用来识别用户的其他东西)存储在账单文件中,然后在 bills
这个接口上启用用户限制资源访问,这样就可以实现了。
我觉得最好是按每个请求来处理这个问题。修改 '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
那预定义的数据库过滤器呢?
bills = {
'datasource': {
'source': 'bills',
'filter': {'field1': 'value1', 'field2': 'value2'}
}
}
source
是一个mongodb的集合;filter
是一个mongodb的查询。这个过滤器会在任何请求到达接口之前自动应用(在客户端查询之前)。
感谢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'] }
现在客户在这个接口上只看到自己的“笔记”。