在sqlalchemy中管理用户权限

时间:2014-03-09 21:45:16

标签: python postgresql sqlalchemy privileges grant

我有一个sqlalchemy脚本,可以创建和使用代表许多用户连接的许多引擎实例。所有引擎都配置为指向同一个postgres数据库。

我有一个引擎,oSuperEngine可以做超级东西。我为鲍勃提供了另一个引擎'oBobsEngine`。

现在我正在做这样的事情:

sSQL = "GRANT ALL PRIVILEGES ON TABLE \"NICE_TABLE\" to bob;"
oSuperEngine.execute(sSQL)

sSQL = "insert into \"NICE_TABLE\" (foo) values (bar)"
oBobsEngine.execute(sSQL) # ERROR HERE

得到:

ProgrammingError: (ProgrammingError) permission denied for relation NICE_TABLE

为什么会这样?

psql中的

\dp告诉我bob从未被授予权限。如果我用超级用户登录psql并手动授予bob他的权限,那么一切正常。在这种情况下,我通过sqlalchemy执行完全相同的命令。

有些东西没有正确冲洗吗? sqlalchemy出于某种原因在尝试授予语句时是否会无声地失败?我怎样才能做到这一点?

不包含更多代码的道歉,代码库是适度错综复杂的。我已经使用日志确认了事件的顺序...如果您需要更多代码以便了解我的问题,请告诉我。

一些日志

2014-03-10 10:07:24,767 - common.sqlalchemy_tools - DEBUG - connection string = "postgresql+psycopg2://super:password@localhost/db_name"
2014-03-10 10:07:24,767 - sqlalchemy.engine.base.Engine - INFO - BEGIN;
2014-03-10 10:07:24,767 - sqlalchemy.engine.base.Engine - INFO - {}
2014-03-10 10:07:24,767 - sqlalchemy.engine.base.Engine - INFO - GRANT ALL PRIVILEGES ON TABLE "MY_TABLE" to bob;
2014-03-10 10:07:24,767 - sqlalchemy.engine.base.Engine - INFO - {}
2014-03-10 10:07:24,768 - sqlalchemy.engine.base.Engine - INFO - COMMIT;
2014-03-10 10:07:24,768 - sqlalchemy.engine.base.Engine - INFO - {}
 ...
2014-03-10 10:07:24,804 - common.sqlalchemy_tools - DEBUG - connection string = "postgresql+psycopg2://bob:password@localhost/db_name"
2014-03-10 10:07:24,814 - sqlalchemy.engine.base.Engine - INFO - BEGIN;
2014-03-10 10:07:24,815 - sqlalchemy.engine.base.Engine - INFO - {}
2014-03-10 10:07:24,827 - sqlalchemy.engine.base.Engine - INFO - insert into "MY_TABLE" (stuff) values (other stuff);
2014-03-10 10:07:24,827 - sqlalchemy.engine.base.Engine - INFO - {}
2014-03-10 10:07:24,828 - sqlalchemy.engine.base.Engine - INFO - ROLLBACK

第一堆东西发生在oSuperEngine,第二堆发生在bob的引擎上。错误看起来像:

ProgrammingError: (ProgrammingError) permission denied for relation MY_TABLE
 'insert into "MY_TABLE" (stuff) values (stuff);' {}

2 个答案:

答案 0 :(得分:6)

我遇到了完全相同的问题。通过这样做固定:

sSQL = "GRANT ALL PRIVILEGES ON TABLE \"NICE_TABLE\" to bob;"
with oSuperEngine.begin() as conn:
    conn.execute(sSQL)

http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#adding-additional-configuration-to-an-existing-sessionmaker

答案 1 :(得分:2)

如果您执行上面的脚本,则会遇到事务隔离问题。实际上我前段时间遇到了类似的问题。这里需要记住的是,Bob的事务没有看到Super引擎所做的更改,因为事务仍在进行,隔离不允许进行非公开读取。 Postgres对此有extensive documentation,但其实质是:在postgres 中无法进行无法读取。

显然,您的解决方案是首先从超级引擎提交更改,然后在另一个事务中使用它。如果没有尝试过,但我的猜测是你必须保持默认的 Read committed 隔离级别(因为更高的隔离不允许检测自事务以来的更改 - 在这种情况下Bobs - 已经启动)。

因此,在执行Bobs查询之前:

oSuperEngine.execute("COMMIT")

然而,这引发了一个侧面问题,有效地打破了交易带来的令人敬畏的事情:由于已经提交了更改,因此无法轻松回滚。你在这里基本上想要的是保存点的反面:

虽然保存点尚未存储对数据库的更改,但它确保回滚只会返回到特定点,而不是一直返回到特定点。你想要相反:将它存储在数据库中,但能够回滚并再次从中删除它。我不知道这样的事情,我高度怀疑它是否存在,因为它违反了事务隔离的原则。

我对此问题的解决方案是编写自定义回滚例程,我会调用异常,以便我可以手动撤消更改。这是相当多的工作,从长远来看是高维护。最后,在我的情况下,我重新考虑了我的解决方案并放弃了多引擎方法(但这是你必须自己做出的决定)。