最近一直有人在QQ群询问怎么设置一个用户对所有表的读权限等有关一次性对数据库或某个模式下所有表增加或移除某一个权限问题
1、对于数据库的所有表需要分多条grant 语句来实现
2、对于某一个模式下的所有表,9.0以前版本也只能通过多条grant语句来实现,而9.0以后则可以通过GRANT xxx ON ALL TABLES IN SCHEMA xxx TO xxx 来实现
3、revoke跟grant情况一下
其实这些我们可以通行守加几个管理函数来实现,封装一下,操作起来不管那个版本都是一样的
一、定义函数
文件 grant_revoke_table_install.sql --安装内容如下 CREATE OR REPLACE FUNCTION public.grant_revoke_table_check(a_schema_name varchar,a_role_name varchar,a_type varchar,a_ver INTEGER) RETURNS TEXT AS $BODY$ DECLARE --传入参数检查 -- a_schema_name:指定某个模式下,不对定是对数据库的所有表 -- a_role_name:指定分配权限的用户 -- a_type:指定分配的权限类型,分别是select ,insert ,update,delete,truncate,references,trugger,all,trucate (9.0后支持truncate) -- a_ver:是传入的版本号,如果调用时传入是0则从系统中获取 v_type VARCHAR; v_ver INTEGER; BEGIN IF v_ver = 0 THEN v_ver:=SUBSTRING(version() FROM 12 FOR 1)::INTEGER; --获取大版本号 ELSE v_ver:=a_ver; END IF; IF a_schema_name != '' THEN--如果指模式,检查模式是否存 PERFORM 1 FROM pg_namespace WHERE nspname = a_schema_name; IF NOT FOUND THEN RETURN '指定的模式 ' || a_schema_name || ' 不存在!'; END IF; END IF; PERFORM 1 FROM pg_roles WHERE rolname = a_role_name ; IF NOT FOUND THEN--检查用户是否存在 RETURN '指定的用户 ' || a_role_name || ' 不存在!'; END IF; v_type:=UPPER(a_type); IF v_type!='SELECT' AND v_type!='INSERT' AND v_type!='UPDATE' AND v_type!='DELETE' AND v_type!='RULE' AND v_type!='REFERENCES' AND v_type!='TRIGGER' AND v_type!='ALL PRIVILEGES' AND v_type!='ALL' THEN IF v_ver >= 9 THEN --9.0版本后验证 IF v_type!='TRUNCATE' THEN RETURN '分配权限方式 ' || v_type || ' 不存在!'; END IF; ELSE RETURN '分配权限方式 ' || v_type || ' 不存在!'; END IF; END IF; RETURN 'OK'; END; $BODY$ LANGUAGE PLPGSQL; COMMENT ON FUNCTION public.grant_revoke_table_check(a_schema_name varchar,a_role_name varchar,a_type varchar,a_ver INTEGER) IS '分配去除权限传入参数检查'; CREATE OR REPLACE FUNCTION public.grant_table (a_schema_name varchar,a_role_name varchar,a_type varchar) RETURNS TEXT AS $BODY$ DECLARE -- a_schema_name:指定某个模式下,不对定是对数据库的所有表 -- a_role_name:指定分配权限的用户 -- a_type:指定分配的权限类型,分别是select ,insert ,update,delete,truncate,references,trugger,all,trucate (9.0后支持truncate) -- 另外这个函数将系统模式pg_catalog,information_schema下的系统表排除在外,一般情况下我们都不建议用户将表立在这两个模式下 v_sql TEXT; v_rec RECORD; v_ret TEXT; v_ver INTEGER; BEGIN v_ver:=SUBSTRING(version() FROM 12 FOR 1)::INTEGER; --获取大版本号 v_ret:=public.grant_revoke_table_check(a_schema_name,a_role_name,a_type,v_ver); IF v_ret!='OK' THEN RETURN v_ret; END IF; IF v_ver < 9 THEN --9.0版本前分配 IF a_schema_name != '' THEN --指定了要设置的权限是某个模式中的表 v_sql:='SELECT schemaname,tablename FROM pg_tables WHERE schemaname=''' || a_sche || ''' AND schemaname!=''pg_catalog'' AND schemaname!=''information_schema'' '; ELSE v_sql:='SELECT schemaname,tablename FROM pg_tables WHERE schemaname!=''pg_catalog'' AND schemaname!=''information_schema'' '; END IF; FOR v_rec IN EXECUTE v_sql LOOP EXECUTE 'GRANT ' || a_type || ' ON "' || v_rec.schemaname || '"."'||v_rec.tablename || '" TO ' || a_role_name; END LOOP; ELSE IF a_schema_name != '' THEN --指定了要设置的权限是某个模式中的表 v_sql:='GRANT '|| a_type || ' ON ALL TABLES IN SCHEMA '|| a_schema_name ||' TO '||a_role_name; EXECUTE v_sql; ELSE v_sql:='SELECT DISTINCT schemaname FROM pg_tables WHERE schemaname!=''pg_catalog'' AND schemaname!=''information_schema'' '; FOR v_rec IN EXECUTE v_sql LOOP EXECUTE 'GRANT ' || a_type || ' ON ALL TABLES IN SCHEMA "' || v_rec.schemaname|| '" TO ' || a_role_name; END LOOP; END IF; END IF; RETURN 'OK'; END; $BODY$ LANGUAGE PLPGSQL; COMMENT ON FUNCTION public.grant_table (a_schema_name varchar,a_role_name varchar,a_type varchar) IS '给指定用户分配某个模式下表的操作权限'; CREATE OR REPLACE FUNCTION public.grant_table (a_role_name varchar,a_type varchar) RETURNS TEXT AS $BODY$ DECLARE BEGIN RETURN public.grant_table('',a_role_name,a_type); END; $BODY$ LANGUAGE PLPGSQL; COMMENT ON FUNCTION public.grant_table (a_role_name varchar,a_type varchar) IS '给指定用户分配所有表的操作权限'; CREATE OR REPLACE FUNCTION public.grant_table (a_role_name varchar) RETURNS TEXT AS $BODY$ DECLARE BEGIN RETURN public.grant_table('',a_role_name,'ALL PRIVILEGES'); END; $BODY$ LANGUAGE PLPGSQL; COMMENT ON FUNCTION public.grant_table (a_role_name varchar) IS '给指定用户分配所有表的所有操作权限'; CREATE OR REPLACE FUNCTION public.revoke_table (a_schema_name varchar,a_role_name varchar,a_type varchar) RETURNS TEXT AS $BODY$ DECLARE -- a_schema_name:指定某个模式下,不对定是对数据库的所有表 -- a_role_name:指定分配权限的用户 -- a_type:指定分配的权限类型,分别是select ,insert ,update,delete,truncate,references,trugger,all,trucate (9.0后支持truncate) -- 另外这个函数将系统模式pg_catalog,information_schema下的系统表排除在外,一般情况下我们都不建议用户将表立在这两个模式下 v_sql TEXT; v_rec RECORD; v_ret TEXT; v_ver INTEGER; BEGIN v_ver:=SUBSTRING(version() FROM 12 FOR 1)::INTEGER; --获取大版本号 v_ret:=public.grant_revoke_table_check(a_schema_name,a_role_name,a_type,v_ver); IF v_ret!='OK' THEN RETURN v_ret; END IF; IF v_ver < 9 THEN --9.0版本前分配 IF a_schema_name != '' THEN --指定了要设置的权限是某个模式中的表 v_sql:='SELECT schemaname,tablename FROM pg_tables WHERE schemaname=''' || a_sche || ''' AND schemaname!=''pg_catalog'' AND schemaname!=''information_schema'' '; ELSE v_sql:='SELECT schemaname,tablename FROM pg_tables WHERE schemaname!=''pg_catalog'' AND schemaname!=''information_schema'' '; END IF; FOR v_rec IN EXECUTE v_sql LOOP EXECUTE 'REVOKE ' || a_type || ' ON "' || v_rec.schemaname || '"."'|| v_rec.tablename || '" FROM ' || a_role_name; END LOOP; ELSE --9.0后的版本 IF a_schema_name != '' THEN --指定了要设置的权限是某个模式中的表 v_sql:='REVOKE '|| a_type || ' ON ALL TABLES IN SCHEMA '|| a_schema_name || ' TO ' || a_role_name; EXECUTE v_sql; ELSE v_sql:='SELECT DISTINCT schemaname FROM pg_tables WHERE schemaname!=''pg_catalog'' AND schemaname!=''information_schema'' '; FOR v_rec IN EXECUTE v_sql LOOP EXECUTE 'REVOKE ' || a_type || ' ON ALL TABLES IN SCHEMA "' || v_rec.schemaname || '" FROM ' || a_role_name; END LOOP; END IF; END IF; RETURN 'OK'; END; $BODY$ LANGUAGE PLPGSQL; COMMENT ON FUNCTION public.revoke_table (a_schema_name varchar,a_role_name varchar,a_type varchar) IS '删除指定用户某个模式下表的操作权限'; CREATE OR REPLACE FUNCTION public.revoke_table (a_role_name varchar,a_type varchar) RETURNS TEXT AS $BODY$ DECLARE BEGIN RETURN public.revoke_table('',a_role_name,a_type); END; $BODY$ LANGUAGE PLPGSQL; COMMENT ON FUNCTION public.revoke_table (a_role_name varchar,a_type varchar) IS '删除指定用户所有表的操作权限'; CREATE OR REPLACE FUNCTION public.revoke_table (a_role_name varchar) RETURNS TEXT AS $BODY$ DECLARE BEGIN RETURN public.revoke_table('',a_role_name,'ALL PRIVILEGES'); END; $BODY$ LANGUAGE PLPGSQL; COMMENT ON FUNCTION public.revoke_table (a_role_name varchar) IS '删除指定用户所有表的所有操作权限'; 文件 grant_revoke_table_uninstall.sql --反安装内容如下 DROP FUNCTION public.grant_revoke_table_check(a_schema_name varchar,a_role_name varchar,a_type varchar,a_ver INTEGER) ; DROP FUNCTION public.grant_table (a_schema_name varchar,a_role_name varchar,a_type varchar); DROP FUNCTION public.grant_table (a_role_name varchar,a_type varchar); DROP FUNCTION public.grant_table (a_role_name varchar); DROP FUNCTION public.revoke_table (a_schema_name varchar,a_role_name varchar,a_type varchar) ; DROP FUNCTION public.revoke_table (a_role_name varchar,a_type varchar) ; DROP FUNCTION public.revoke_table (a_role_name varchar) ;
二、测试结果
Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。 C:\Users\pgsql>h: H:\>cd pgsql H:\pgsql>cd bin H:\pgsql\bin>setenv H:\pgsql\bin>SET PGDATA=H:/pgsql/data H:\pgsql\bin>SET PGUSER=postgres H:\pgsql\bin>SET PGDATABASE=cysoft_database H:\pgsql\bin>SET PGPORT=5432 H:\pgsql\bin>SET PGHOST=127.0.0.1 H:\pgsql\bin>SET PGCLIENTENCODING=gbk H:\pgsql\bin>psql -d test -U postres psql: FATAL: role "postres" does not exist H:\pgsql\bin>psql -d test -U postgres Welcome to psql 8.2.4, the PostgreSQL interactive terminal. Type: \copyright for distribution terms \h for help with SQL commands \? for help with psql commands \g or terminate with semicolon to execute query \q to quit test=# \e CREATE FUNCTION COMMENT CREATE FUNCTION COMMENT CREATE FUNCTION COMMENT CREATE FUNCTION COMMENT CREATE FUNCTION COMMENT CREATE FUNCTION COMMENT CREATE FUNCTION COMMENT test=# CREATE ROLE pgsqldb WITH LOGIN; CREATE ROLE test=# \c test pgsqldb You are now connected to database "test" as user "pgsqldb". test=> select * from t1; ERROR: permission denied for relation t1 test=> select * from t2; ERROR: permission denied for relation t2 test=> \c test postgres You are now connected to database "test" as user "postgres". test=# select grant_table('pgsqldb','select'); grant_table ------------- OK (1 行) test=# \c test pgsqldb You are now connected to database "test" as user "pgsqldb". test=> select * from t1; id | mc ----+--------- 1 | 阿弟 2 | laser 3 | postbbs (3 rows) test=> select * from t2; id | t1_id | rq ----+-------+------------ 1 | 1 | 2013-04-11 2 | 1 | 2013-04-12 (2 rows) test=> insert into t1 values (66666,'pgsqldb'); ERROR: permission denied for relation t1 test=> \c test postgres You are now connected to database "test" as user "postgres". test=# select grant_table('pgsqldb','insert'); grant_table ------------- OK (1 行) test=# \c test pgsqldb You are now connected to database "test" as user "pgsqldb". test=> insert into t1 values (66666,'pgsqldb'); INSERT 89365707 1 test=> update t1 set id =88888 where id=66666; ERROR: permission denied for relation t1 test=> delete from t1 where id=66666; ERROR: permission denied for relation t1 test=> \c test postgres You are now connected to database "test" as user "postgres". test=# select grant_table('pgsqldb','all'); grant_table ------------- OK (1 行) test=# \c test pgsqldb You are now connected to database "test" as user "pgsqldb". test=> update t1 set id =88888 where id=66666; UPDATE 1 ^ test=> delete from t1 where id=88888; DELETE 1 test=> \c test postgres You are now connected to database "test" as user "postgres". test=# select grant_table('a','pgsqldb','all'); grant_table ---------------------- 指定的模式 a 不存在! (1 行) test=# select grant_table('','pgsqldb1','all'); grant_table ----------------------------- 指定的用户 pgsqldb1 不存在! (1 行) test=# select grant_table('','pgsqldb','all1'); grant_table --------------------------- 分配权限方式 ALL1 不存在! (1 行) test=# select grant_table('','pgsqldb','truncate'); grant_table ------------------------------- 分配权限方式 TRUNCATE 不存在! (1 行) test=# select revoke_table('pgsqldb'); revoke_table -------------- OK (1 行) test=# \c test pgsqldb You are now connected to database "test" as user "pgsqldb". test=> select * from t1; ERROR: permission denied for relation t1 test=> select * from t2; ERROR: permission denied for relation t2 test=> delete from t1; ERROR: permission denied for relation t1 test=> update t1 set id=111; ERROR: permission denied for relation t1 test=> insert into t1 values(1,'pgsqldb'); ERROR: permission denied for relation t1 test=>
时间: 2024-11-01 17:09:02