6

这是场景(简化示例):

我有一个名为 ABC 的 Oracle 用户/模式。ABC 拥有一个名为 TRN 的表。客户端代码作为 ABC 连接到数据库并从 ABC.TRN 中选择。

到目前为止,一切都很好。但是,我不希望客户端代码指定 Oracle 模式名称。现在我想我已经删除了客户端代码中所有引用模式的引用,但我想对此进行测试以确保。

所以我想创建一个名为 DEF 的新用户/模式,客户端将使用它来连接到数据库。当客户端应用程序从 ABC.TRN 中选择时,它必须给出错误。但是,如果客户端应用程序从 TRN(无模式名称)中选择,它必须返回数据。

有没有办法做到这一点?请注意,DEF 必须与 ABC 在同一个数据库上,只有一个表 TRN 表(由 ABC 拥有),我不能使用数据库链接。

我尝试使用指向 ABC.TRN 的同义词创建一个新的 XYZ 用户,并赋予它对 ABC.TRN 的选择权限。然后,我使用指向 XYZ.TRN 的同义词创建了 DEF 用户,并赋予 DEF 对 XYZ.TRN 的选择权限。这可行,但 Oracle 足够聪明,知道如果 DEF 有权从 XYZ.TRN 中进行选择,那么它也有权从 ABC.TRN 中进行选择,从而违背了本练习的目的,因为我希望这个案例给出错误。

交给你...

4

4 回答 4

7

没有简单的方法可以做到这一点。

一种方法是政治性的:进行代码审查,也许通过代码库的自动搜索,当人们这样做时,只是拍拍手腕。

架构方法类似于您的三个模式结构,但有一个微妙的变化:中间的模式使用视图。因此,模式 ABC 拥有表并将它们的权限授予模式 XYZ。模式 XYZ 针对这些表构建简单视图(SELECT *,无 WHERE 子句)并将视图的权限授予模式 DEF。Schema DEF 只能从 XYZ 对象中选择。

当然,所有这些努力仍然不会阻止开发人员编码SELECT * FROM xyz.whatever。在这种情况下,我建议您参考我的第一个建议 8-)


实际上,有一种非常非常邪恶的方法可以做到这一点。在面向应用的架构 (DEF) 中使用同义词,然后更改拥有数据的架构 (ABC) 的名称。

当然,只有在您的安装脚本完全参数化且没有自己的硬编码模式名称的情况下,您才应该尝试这种策略。

于 2011-09-27T14:22:37.543 回答
5

你真的需要抛出错误吗?或者您是否只需要验证应用程序没有使用完全限定名称(即ABC.TRN)?

假设您只对验证应用程序没有使用完全限定名称感兴趣并且抛出错误只是您想到通知您的机制,您可能可以通过V$SQL在应用程序运行时查询来验证代码。 V$SQL列出了 Oracle 中共享池中的所有 SQL 语句。如果您在应用程序运行时定期查询该表,您将看到它发出的所有 SQL 语句。然后,您可以记录任何使用完全限定名称的语句。

例如

CREATE OR PROCEDURE look_for_abc_trn
AS
BEGIN
  FOR x IN (SELECT *
              FROM v$sql
             WHERE upper(sql_fulltext) LIKE '%ABC.TRN%')
  LOOP
    INSERT INTO log_of_bad_sql( sql_fulltext, <<other columns>> )
      VALUES( x.sql_fulltext, <<other columns>> );
  END LOOP;
END;

如果您在应用程序运行时每隔几分钟运行一次该过程,您将看到任何使用完全限定名称的 SQL 并将该语句记录在LOG_OF_BAD_SQL表中。对于编写良好的系统来说,每隔几分钟可能就有点过分了,您只需要确保它的运行频率高于共享池中语句的老化频率。如果您的应用程序未正确使用绑定变量,则可能需要每隔几分钟进行一次,以免遗漏任何内容。

于 2011-09-27T14:23:48.047 回答
1

改变会话怎么样?

         ALTER SESSION SET CURRENT_SCHEMA = schema

这将允许您以用户身份登录,该用户已被授予对模式 X 拥有的表的选择权限,并执行将会话更改为模式 X 的 SP。前端代码不会知道这已经发生.

但是,如果您的前端代码指定了模式 X:

           select * from X.tableName

我认为它不会引发错误。

也许您可以解释为什么客户端代码在使用正确的当前模式名称时收到错误很重要?

是否可以创建一个新模式,转移旧模式对象的所有者,然后删​​除旧模式,然后使用上述方法?

PS 请参阅登录后触发器: http: //psoug.org/reference/system_trigger.html

PPS 既然您已经详细说明了您的要求:

...该表可能是使用数据库链接的同义词,或者该表可能由多个模式托管,每个模式用于不同的版本。它应该留给数据库来解析客户端应用程序引用的对象的实际位置。

如果对象的位置不在 CURRENT_SCHEMA 中而是在其他模式中,例如,这两个模式恰好都有名为 CUSTOMER 的表,数据库引擎将不知道客户端应用程序发送给它的语句应该是引用如果表名不是那么限定,则使用另一个模式。这意味着引擎不具备一定程度的元知识,尽管它为开发人员提供了以存储过程和触发器的形式创建此类智能以及授予/撤销对对象的控制的工具。

将这种智能置于后端的最佳成功机会是撤销对表和视图的所有直接权限,并要求客户端应用程序通过存储过程访问对象,因为数据库引擎本身不知道应用程序发布之类的事情水平。我认为没有纯粹的声明方式来完成它。它在很大程度上必须是程序性的。您自己的后端逻辑必须负责在不同模式中的同名对象之间进行仲裁。也就是说,AFTER LOGON 触发器和 ALTER SCHEMA 等功能应该对您有所帮助。

于 2011-09-27T14:10:30.433 回答
0

你不能这样做。同义词只不过是指向其他模式对象的指针。您授予对实际对象的访问权限,而不是同义词。来自 Oracle 文档:

http://download.oracle.com/docs/cd/B28359_01/server.111/b28310/views003.htm

同义词本身是不安全的。当您授予对同义词的对象权限时,您实际上是在授予对基础对象的权限,并且同义词仅充当 GRANT 语句中对象的别名。

于 2011-09-27T14:14:31.003 回答