사용자가 속한 모든 역할 (상속 된 역할 포함)을 얻는 방법은 무엇입니까?


23

두 개의 Postgresql 데이터베이스 그룹 인 "authors"및 "editors"와 두 명의 사용자 "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이 속한 역할 (바람직하게는 그들의 역할) 목록을 반환하는 수행자 함수를 작성하고 싶습니다.

create or replace function get_all_roles() returns oid[] ...

맥스웰, 저자 및 편집자에 대한 OID를 반환해야합니다.

그러나 상속이있을 때 어떻게 해야할지 모르겠습니다.

답변:


23

당신은 시스템 A와 카탈로그를 조회 할 수 있습니다 재귀 쿼리 , 특히를 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 FROM cte;

BTW INHERIT는 기본 동작이며 CREATE ROLE철자가 필요하지 않습니다.

BTW2 : 순환 종속성이 불가능합니다. Postgres는이를 허용하지 않습니다. 따라서 확인하지 않아도됩니다.


18

짧은 버전 :

SELECT a.oid 
FROM pg_authid a 
WHERE pg_has_role('maxwell', a.oid, 'member');

여기서 우리 는 멤버쉽을 테스트하기 위해 역할 이름을 주제 및 역할로 사용 하는 버전을pg_has_role 사용 하고 , 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)쿼리 할 필요없이 OID에서 역할 이름을 가져 오는 데 사용할 수 있습니다 pg_authid.

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');

2
어쨌든 +1입니다. pg_has_role()재귀 쿼리보다 약간 빠르기 때문에 중요하지 않습니다. 그러나 마지막 한 가지는 슈퍼 슈퍼에 대한 모든 역할을 반환 하며 이는 반가운 부작용 일 수 있습니다. 결과가 내 쿼리와 다른 곳입니다.
Erwin Brandstetter

16

이것은 수퍼 유저가 아닌 사용자가 직접 사용할 수있는 Craig Ringer의 답변 을 단순화 한 버전입니다 .

 SELECT oid, rolname FROM pg_roles WHERE
   pg_has_role( 'maxwell', oid, 'member');

pg_rolespg_authid와 달리 비밀번호를 공개하지 않으므로 공개적 으로 액세스 할 수 있는 관점입니다 pg_authid. 베이스 oid도 뷰로 내보내집니다. 암호가 필요하지 않은 경우 전용 수퍼 유저 소유 기능을 만들 필요는 없습니다.


3

여기에 내가 가져 가라. 하나의 특정 사용자 또는 모든 사용자에게 적용됩니다.

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'

1
이전 답변과 어떻게 다르고 개선되었는지 설명하면 훨씬 향상 될 것입니다. 추가 정보를 답변으로 직접 편집 할 수 있습니다.
Michael Green

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.


0

현재 활성 역할의 모든 역할을 알고 싶은 경우 :

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;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.