sqlalchemy查询的前过滤器用户访问的最佳方式是什么?

时间:2010-05-21 20:41:08

标签: filter sqlalchemy acl

我一直在关注他们维基上的sqlalchemy食谱,但不知道哪一个最适合我实施的目的。

我的表中的每一行都有一个与之关联的user_id。现在,对于每个查询,我查询当前登录的用户的id,然后按照我感兴趣的标准进行查询。我担心的是开发人员可能忘记将此过滤器添加到查询中(存在巨大的安全风险) )。因此,我想根据当前用户的管理员权限设置一个全局过滤器,以过滤登录用户可以看到的内容。

感谢您的帮助。感谢。

3 个答案:

答案 0 :(得分:2)

下面是简化的重新定义的查询构造函数,用于过滤所有模型查询(包括关系)。您可以将其作为query_cls参数传递给sessionmaker。当会话已经可用时,用户ID参数不需要是全局的。

class HackedQuery(Query):

    def get(self, ident):
        # Use default implementation when there is no condition
        if not self._criterion:
            return Query.get(self, ident)
        # Copied from Query implementation with some changes.
        if hasattr(ident, '__composite_values__'):
            ident = ident.__composite_values__()
        mapper = self._only_mapper_zero(
                    "get() can only be used against a single mapped class.")
        key = mapper.identity_key_from_primary_key(ident)
        if ident is None:
            if key is not None:
                ident = key[1]
        else:
            from sqlalchemy import util
            ident = util.to_list(ident)
        if ident is not None:
            columns = list(mapper.primary_key)
            if len(columns)!=len(ident):
                raise TypeError("Number of values doen't match number "
                                'of columns in primary key')
            params = {}
            for column, value in zip(columns, ident):
                params[column.key] = value
            return self.filter_by(**params).first()


def QueryPublic(entities, session=None):
    # It's not directly related to the problem, but is useful too.
    query = HackedQuery(entities, session).with_polymorphic('*')
    # Version for several entities needs thorough testing, so we 
    # don't use it yet.
    assert len(entities)==1, entities
    cls = _class_to_mapper(entities[0]).class_
    public_condition = getattr(cls, 'public_condition', None)
    if public_condition is not None:
        query = query.filter(public_condition)
    return query

它仅适用于单个模型查询,并且有很多工作可以使其适用于其他情况。我希望看到一个精心设计的版本,因为它必须具有大多数Web应用程序的功能。它使用存储在每个模型类中的固定条件,因此您必须根据需要对其进行修改。

答案 1 :(得分:1)

这是一个非常天真的实现,它假定用户已经存储了属性/属性self.current_user

class YourBaseRequestHandler(object):

    @property
    def current_user(self):
        """The current user logged in."""
        pass

    def query(self, session, entities):
        """Use this method instead of :method:`Session.query()
        <sqlalchemy.orm.session.Session.query>`.

        """
        return session.query(entities).filter_by(user_id=self.current_user.id)

答案 2 :(得分:1)

我编写了一个SQLAlchemy扩展,我认为你所做的是:https://github.com/mwhite/multialchemy

它通过代理Query._from_objQueryContext._froms属性的更改来完成此操作,这是要从中选择的表最终设置的位置。