2つのPostgresqlデータベースグループ、「作成者」と「編集者」、および2人のユーザー「maxwell」と「ernest」があるとします。
create role authors;
create role editors;
create user maxwell;
create user ernest;
grant authors to editors; --editors can do what authors can do
grant editors to maxwell; --maxwell is an editor
grant authors to ernest; --ernest is an author
Maxwellが属しているロール(できればそれらのOID)のリストを返す、次のようなパフォーマンス関数を記述したいと思います。
create or replace function get_all_roles() returns oid[] ...
Maxwell、作者、編集者(アーネストではない)のOIDを返す必要があります。
しかし、相続があるときにどうすればいいのかわかりません。
再帰クエリ 、特に pg_auth_members
:
WITH RECURSIVE cte AS (
SELECT oid FROM pg_roles WHERE rolname = 'maxwell'
UNION ALL
SELECT m.roleid
FROM cte
JOIN pg_auth_members m ON m.member = cte.oid
)
SELECT oid, oid::regrole::text AS rolename FROM cte; -- oid & name
オブジェクト識別子タイプregrole
へのキャストに関するマニュアル。
ところで、INHERIT
は CREATE ROLE
と入力する必要はありません。
ところで:循環依存はできません。 Postgresはそれを許可しません。そのため、これを確認する必要はありません。
短縮版:
_SELECT a.oid
FROM pg_authid a
WHERE pg_has_role('maxwell', a.oid, 'member');
_
ここでは ロール名をサブジェクトとして使用する_pg_has_role
_のバージョンと、メンバーシップをテストするロールoid を使用し、member
モードを渡して継承されたメンバーシップをテストします。
_pg_has_role
_を使用する利点は、PostgreSQLのロール情報の内部キャッシュを使用して、メンバーシップクエリをすばやく満たすことです。
_SECURITY DEFINER
_はアクセスを制限されているため、これを_pg_authid
_関数でラップすることができます。何かのようなもの:
_CREATE OR REPLACE FUNCTION user_role_memberships(text)
RETURNS SETOF oid
LANGUAGE sql
SECURITY DEFINER
SET search_path = pg_catalog, pg_temp
AS $$
SELECT a.oid
FROM pg_authid a
WHERE pg_has_role($1, a.oid, 'member');
$$;
REVOKE EXECUTE ON FUNCTION user_role_memberships(text) FROM public;
GRANT EXECUTE ON FUNCTION user_role_memberships(text) TO ...whoever...;
_
pg_get_userbyid(oid)
を使用すると、_pg_authid
_をクエリする必要なく、oidからロール名を取得できます。
_SELECT a.oid AS member_oid, pg_get_userbyid(oid) AS member_name
FROM pg_authid a
WHERE pg_has_role('maxwell', a.oid, 'member');
_
これは、スーパーユーザー以外が直接使用できる Craig Ringerの回答 の簡易バージョンです。
SELECT oid, rolname FROM pg_roles WHERE
pg_has_role( 'maxwell', oid, 'member');
pg_roles
は、pg_authid
とは異なり、パスワードを明らかにしないため、基本的にはpg_authid
の一般公開されたビューです。ベースoid
もビューにエクスポートされます。パスワードが不要な場合は、専用のスーパーユーザーが所有する関数を作成しても意味がありません。
これが私の見解です。特定のユーザーまたはすべてのユーザーに対して機能します。
select a.oid as user_role_id
, a.rolname as user_role_name
, b.roleid as other_role_id
, c.rolname as other_role_name
from pg_roles a
inner join pg_auth_members b on a.oid=b.member
inner join pg_roles c on b.roleid=c.oid
where a.rolname = 'user_1'
これでうまくいくと思います
SELECT
oid
FROM
pg_roles
WHERE
oid IN (SELECT
roleid
FROM
pg_auth_members
WHERE
member=(SELECT oid FROM pg_roles WHERE rolname='maxwell'));
ロール名を取得する場合は、最初のoid
をrolname
に置き換えます。
現在アクティブな役割のすべての役割を知りたい場合:
CREATE OR REPLACE VIEW public.my_roles
AS WITH RECURSIVE cte AS (
SELECT pg_roles.oid,
pg_roles.rolname
FROM pg_roles
WHERE pg_roles.rolname = CURRENT_USER
UNION ALL
SELECT m.roleid,
pgr.rolname
FROM cte cte_1
JOIN pg_auth_members m ON m.member = cte_1.oid
JOIN pg_roles pgr ON pgr.oid = m.roleid
)
SELECT array_agg(cte.rolname) AS my_roles
FROM cte;