Postgresql 如何防止特定列通过RESTAPI更新显式设置其值?

Postgresql 如何防止特定列通过RESTAPI更新显式设置其值?,postgresql,rest,Postgresql,Rest,我有多个表,我希望用户能够通过RESTAPI进行更新,而且很多表(如果不是全部的话)都有具有合理默认值的列 web应用程序本身可以设计为隐藏这些列,但我也希望允许直接访问api,以便其他人可以使用他们认为合适的数据 不幸的是,这意味着他们可以将默认列显式地设置为1972,或者将id列设置为任意值 在后端Postgres 9.4上有哪些机制可以限制这一点?您应该在API级别这样做 如果任何人发出格式错误的请求,例如,他们想要覆盖ID或时间戳,请使用正确的状态代码(可能是400)进行回答,并使用有意

我有多个表,我希望用户能够通过RESTAPI进行更新,而且很多表(如果不是全部的话)都有具有合理默认值的列

web应用程序本身可以设计为隐藏这些列,但我也希望允许直接访问api,以便其他人可以使用他们认为合适的数据

不幸的是,这意味着他们可以将默认列显式地设置为1972,或者将id列设置为任意值


在后端Postgres 9.4上有哪些机制可以限制这一点?

您应该在API级别这样做

如果任何人发出格式错误的请求,例如,他们想要覆盖ID或时间戳,请使用正确的状态代码(可能是400)进行回答,并使用有意义的消息进行修改,例如,您试图更新,这是只读的

如果您真的坚持在db级别处理,他们建议:

最简单的方法是创建更新前触发器,该触发器将比较旧行和新行,并在禁止更改行时引发异常


您应该在API级别执行此操作

如果任何人发出格式错误的请求,例如,他们想要覆盖ID或时间戳,请使用正确的状态代码(可能是400)进行回答,并使用有意义的消息进行修改,例如,您试图更新,这是只读的

如果您真的坚持在db级别处理,他们建议:

最简单的方法是创建更新前触发器,该触发器将比较旧行和新行,并在禁止更改行时引发异常


PostgreSQL自9.3版起就支持,因此您可以公开具有有限列子集的视图,而不是公开实际表:

CREATE TABLE foo (id SERIAL, name VARCHAR, protected NUMERIC DEFAULT 0);
CREATE VIEW foo_v AS SELECT name FROM foo;
现在,您可以执行以下操作:

INSERT INTO foo_v VALUES ('foobar');
UPDATE foo_v SET name = 'foo' WHERE name = 'foobar';

如果需要更多信息,可以使用INSERT/UPDATE或INSERT。

PostgreSQL,因为版本9.3支持,所以不公开实际表,您可以公开具有有限列子集的视图:

CREATE TABLE foo (id SERIAL, name VARCHAR, protected NUMERIC DEFAULT 0);
CREATE VIEW foo_v AS SELECT name FROM foo;
现在,您可以执行以下操作:

INSERT INTO foo_v VALUES ('foobar');
UPDATE foo_v SET name = 'foo' WHERE name = 'foobar';

如果您需要更多,可以使用INSERT/UPDATE或INSERT替代。

我有幸尝试了Postgres的列级授权。在开发环境中,确保您的数据库用户不是超级用户非常重要。如果是超级用户,请创建第二个超级用户,然后使用alter role从开发人员帐户中撤销它

然后,可以在表上运行与以下类似的命令:

revoke all on schema.table from dev_user;
grant select, delete, references on schema.table to dev_user;
grant update (col1, col2) on schema.table to dev_user;
grant insert (col1, col2) on schema.table to dev_user;
一些警告:

如果另一个表将对其进行访问,请记住也要授予引用。 记住给出col1和col2以及任何其他sane默认值,因为API将无法以任何方式更改它们。 在从DEV帐户取消超级用户状态之前,不要忘记创建第二个超级用户帐户。这是可能恢复的,但这是一个巨大的痛苦。 此外,如果要将这些授予/撤销与create table语句保存在同一个文件中,则可以使用以下表单:

do $$begin execute 'grant select, delete, references on schema.table to ' || current_user; end$$;

通过这种方式,这些语句将正确地转换为产品,而产品可能不会使用与开发中相同的用户名。

我有幸尝试了Postgres的列级授权。在开发环境中,确保您的数据库用户不是超级用户非常重要。如果是超级用户,请创建第二个超级用户,然后使用alter role从开发人员帐户中撤销它

然后,可以在表上运行与以下类似的命令:

revoke all on schema.table from dev_user;
grant select, delete, references on schema.table to dev_user;
grant update (col1, col2) on schema.table to dev_user;
grant insert (col1, col2) on schema.table to dev_user;
一些警告:

如果另一个表将对其进行访问,请记住也要授予引用。 记住给出col1和col2以及任何其他sane默认值,因为API将无法以任何方式更改它们。 在从DEV帐户取消超级用户状态之前,不要忘记创建第二个超级用户帐户。这是可能恢复的,但这是一个巨大的痛苦。 此外,如果要将这些授予/撤销与create table语句保存在同一个文件中,则可以使用以下表单:

do $$begin execute 'grant select, delete, references on schema.table to ' || current_user; end$$;

这样,语句将正确地转换为生产,生产可能不会使用与开发中相同的用户名。

我不坚持在db级别处理它,但我可以在api代码中的所有表中重复使用相同的代码。我已经参数化了查询本身,并检查用户传递的任何表或列名以确保其有效。如果我在代码中这样做,那么我需要为每个表创建一个新的代码页,以便管理哪些列允许更新或不允许更新。db看起来可能更优雅。我不坚持在db级别处理它,但我可以在api代码中的所有表中重用相同的代码。我已经参数化了查询本身,并检查用户传递的任何表或列名以确保其有效。如果我在代码中这样做,那么我需要为每个表创建一个新的代码页,以便管理哪些列允许更新或不允许更新。db看起来可能更优雅。