【发布时间】:2010-12-23 20:51:19
【问题描述】:
我有一个基于 Pylons 的 Web 应用程序,它通过 Sqlalchemy (v0.5) 连接到 Postgres 数据库。为了安全起见,我没有使用普通的 Postgres 用户(例如“webapp”),而不是遵循简单 Web 应用程序的典型模式(如几乎所有教程中所见),而是要求用户输入自己的 Postgres 用户名和密码,并使用它来建立连接。这意味着我们可以充分利用 Postgres 的安全性。
更复杂的是,有两个独立的数据库要连接。尽管它们目前在同一个 Postgres 集群中,但它们需要能够在以后移动到不同的主机。
我们正在使用 sqlalchemy 的 declarative 包,虽然我看不出这与此事有任何关系。
大多数 sqlalchemy 示例都展示了一些简单的方法,例如在应用程序启动时使用通用数据库用户 ID 和密码设置一次元数据,通过 Web 应用程序使用。这通常使用 Metadata.bind = create_engine() 完成,有时甚至在数据库模型文件中的模块级别。
我的问题是,我们如何才能在用户登录之前推迟建立连接,然后(当然)为每个后续请求重新使用这些连接,或者使用相同的凭据重新建立它们。
我们有这个工作——我们认为——但我不仅不确定它的安全性,而且我还认为它在这种情况下看起来非常重要。
在 BaseController 的 __call__ 方法中,我们从 Web 会话中检索用户 ID 和密码,为每个数据库调用一次 sqlalchemy create_engine(),然后调用一个例程重复调用 Session.bind_mapper(),每个表一次可能在这些连接中的每一个上都被引用,即使任何给定的请求通常只引用一个或两个表。它看起来像这样:
# in lib/base.py on the BaseController class
def __call__(self, environ, start_response):
# note: web session contains {'username': XXX, 'password': YYY}
url1 = 'postgres://%(username)s:%(password)s@server1/finance' % session
url2 = 'postgres://%(username)s:%(password)s@server2/staff' % session
finance = create_engine(url1)
staff = create_engine(url2)
db_configure(staff, finance) # see below
... etc
# in another file
Session = scoped_session(sessionmaker())
def db_configure(staff, finance):
s = Session()
from db.finance import Employee, Customer, Invoice
for c in [
Employee,
Customer,
Invoice,
]:
s.bind_mapper(c, finance)
from db.staff import Project, Hour
for c in [
Project,
Hour,
]:
s.bind_mapper(c, staff)
s.close() # prevents leaking connections between sessions?
所以 create_engine() 调用发生在每个请求上......我可以看到这是需要的,并且连接池可能会缓存它们并明智地做事。
但是在 every 请求时为 each 表调用一次 Session.bind_mapper() 吗?似乎必须有更好的方法。
显然,由于对强大安全性的渴望是所有这一切的基础,我们不希望为高安全性用户建立的连接无意中被低安全性用户在以后的请求中使用。
【问题讨论】:
标签: python postgresql web-applications sqlalchemy pylons