我可以在触发器中创建用户吗?
Posted
技术标签:
【中文标题】我可以在触发器中创建用户吗?【英文标题】:Can I create a user inside a trigger? 【发布时间】:2014-12-19 02:54:45 【问题描述】:我想知道是否可以在触发器中创建用户。尽管我认为我的代码在语法上是正确的,但我遇到了错误。
这里是代码
CREATE OR REPLACE TRIGGER addUser
BEFORE INSERT
ON PLSQL_TEST_USERS
FOR EACH ROW
DECLARE
n VARCHAR2(20) := :new.name;
p VARCHAR2(20) := :new.password;
BEGIN
dbms_output.put_line(n);
EXECUTE IMMEDIATE ('CREATE USER n IDENTIFIED BY p');
END;
/
那么有可能做到吗?
这是我得到的错误:
插入 PLSQL_TEST_USERS 值(1,'rob','asdf') 错误报告 - SQL 错误:ORA-04092:无法在触发器中提交 ORA-06512:在“SYSTEM.ADDUSER”,第 6 行 ORA-04088: 执行触发器“SYSTEM.ADDUSER”时出错 04092. 00000 - “不能在触发器中 %s” *原因:触发器试图提交或回滚。 *操作:重写触发器,使其不提交或回滚。
【问题讨论】:
【参考方案1】:不,你不能正确地做到这一点。
您不能在触发器内提交(通常,我将在下面讨论异常)。像CREATE USER
这样的 DDL 发出两个隐式提交(一个在语句之前,一个在语句之后),因此您不能将 DDL 放在触发器中。
如果您声明触发器使用自治事务,则会出现关于在触发器内提交的规则的例外情况。但这并不能正确解决问题,原因有几个。首先,顾名思义,自治事务是自治的,因此即使触发语句回滚,它也会被提交。这意味着,如果INSERT
语句成功插入一行但该更改被回滚,则自治事务仍然提交,因此您最终会创建一个用户,但plsql_test_users
表中没有行。出于写一致性的原因,Oracle 也可能在内部回滚并重新执行一条语句,这会导致自治事务被执行两次,第二次会因为用户已经存在而失败。自治事务实际上应该只用于您想要记录信息的情况,无论基础更改是否成功(即记录尝试的登录或密码更改,以便即使不成功的登录或密码更改不会改变您也可以检测攻击数据的状态)。
您可以让您的触发器调用dbms_job.submit
提交一个后台作业,该作业将在实际创建用户的语句提交(如果确实提交)后不久运行。这将涉及添加到表的行和正在创建的用户之间的小延迟,但它至少在事务上是正确的(延迟可能会变大,具体取决于您尝试创建的用户数量和背景数量你允许的工作)。不幸的是,您必须使用较旧的 dbms_job
包而不是较新的 dbms_scheduler
包来提交作业,因为较新的包包含隐式提交。
如果您确实使用了后台作业路径,请注意传递给EXECUTE IMMEDIATE
的语句不能引用局部变量中的值——当执行动态 SQL 语句时,这些变量不在范围内。当你写
EXECUTE IMMEDIATE 'CREATE USER n IDENTIFIED BY p';
n
和 p
不是指您定义的局部变量,它们是文字标识符。这将创建一个具有单字符密码“p”的用户“n”。假设您想使用表中的用户名和密码,您需要在组装动态 SQL 语句时使用它们。类似的东西
EXECUTE IMMEDIATE
'CREATE USER ' || :new.name ||
' IDENTIFIED BY ' || :new.password;
这一切都引出了一个问题,即您为什么要尝试将信息存储在两个地方。您似乎不太可能真的想要一个表plsql_test_users
,其中包含一堆也是 Oracle 用户的用户名和密码。您要么希望 Oracle 处理身份验证,要么希望让您的应用程序处理身份验证,您不希望每个人都认为它正在处理身份验证(例如,当密码更改而另一个更改时会发生这种情况)。如果您的应用程序要处理身份验证,您永远不会存储密码(或加密密码)。您将使用盐存储密码的哈希值(在 RAW 列中)。然后,当用户在登录时提供密码并比较哈希值时,您将计算并验证哈希值。
【讨论】:
以上是关于我可以在触发器中创建用户吗?的主要内容,如果未能解决你的问题,请参考以下文章