2010-05-21 90 views
14

我一直在尋找他們的維基上的sqlalchemy食譜,但不知道哪一個是最好實施我想要做的。預過濾用戶訪問sqlalchemy查詢的最佳方式是什麼?

我表格中的每一行都有一個與它關聯的user_id。現在,對於每個查詢,我都會查詢當前登錄的用戶的id,然後按照我感興趣的標準進行查詢。我擔心的是開發人員可能會忘記將此過濾器添加到查詢中(巨大的安全風險)。因此,我想根據當前用戶的管理權限設置一個全局過濾器來過濾登錄用戶可以看到的內容。

感謝您的幫助。謝謝。

+3

你有沒有想過使用數據庫安全系統來實現這一目標?例如,Oracle通過其VPD功能提供此功能(http://www.oracle.com/technology/deploy/security/database-security/virtual-private-database/index.html)。您也可以在其他數據庫中實現類似的功能(例如http://ddj.com/database/215900773和http://technet.microsoft.com/en-gb/library/cc966395.aspx)。只需谷歌「行級安全RDBSName」。 – stephan 2010-05-26 15:07:22

+0

,或在所有添加適當限制的表上設置視圖或規則,並剝奪用戶直接讀取底層表的權限。 http://www.postgresql.org/docs/8.4/interactive/rules.html – 2010-09-23 21:42:54

回答

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

因此,我最終結合使用http://www.sqlalchemy.org/trac/wiki/UsageRecipes/PreFilteredQuery進行了解答。有沒有一種方法可以在模型類級別爲sessionmaker指定query_cls?並非所有模型都有我想過濾的這一列。 – steve 2010-12-25 18:28:42

+0

噢,我在模型中查詢= Session.query_property(FilterByUserQuery)。非常感謝。 – steve 2010-12-25 20:02:56

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) 
1

我寫了一個SQLAlchemy的擴展,我覺得做你所描述的:https://github.com/mwhite/multialchemy

它通過進行代理更改Query._from_objQueryContext._froms性能,這哪裏是表,從最終獲取設置選擇執行此操作。

相關問題