连接到数据库后切换角色


70

在初始连接后与postgres交互时,是否可以更改用户正在使用的postgresql角色?

该数据库将在Web应用程序中使用,我想在具有连接池的表和模式上采用数据库级规则。通过阅读postgresql文档,如果我最初以超级用户角色作为用户连接,则似乎可以切换角色,但我希望最初以最小的权限作为用户连接并根据需要进行切换。切换时不必指定用户密码就可以了(事实上,我更喜欢这样)。

我想念什么?

更新:我已经尝试了这两种方法,SET ROLESET SESSION AUTHORIZATION按照@Milen的建议进行了尝试,但是如果用户不是超级用户,那么这两个命令似乎都不起作用:

$ psql -U test
psql (8.4.4)
Type "help" for help.

test=> \du test
          List of roles
 Role name | Attributes |   Member of    
-----------+------------+----------------
 test      |            | {connect_only}

test=> \du test2
          List of roles
 Role name | Attributes |   Member of    
-----------+------------+----------------
 test2     |            | {connect_only}

test=> set role test2;
ERROR:  permission denied to set role "test2"
test=> \q

Answers:


54
--create a user that you want to use the database as:

create role neil;

--create the user for the web server to connect as:

create role webgui noinherit login password 's3cr3t';

--let webgui set role to neil:

grant neil to webgui; --this looks backwards but is correct.

webgui现在在neil群组中,因此webgui可以致电set role neil。但是,webgui没有继承neil的权限。

稍后,以webgui身份登录:

psql -d some_database -U webgui
(enter s3cr3t as password)

set role neil;

webgui不需要superuser此权限。

您想要set role在数据库会话的开始时,然后在会话结束时将其重置。在Web应用程序中,这相当于分别从数据库连接池中获取连接并释放它。这是一个使用Tomcat的连接池和Spring Security的示例:

public class SetRoleJdbcInterceptor extends JdbcInterceptor {

    @Override
    public void reset(ConnectionPool connectionPool, PooledConnection pooledConnection) {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if(authentication != null) {
            try {

                /* 
                  use OWASP's ESAPI to encode the username to avoid SQL Injection. Can't use parameters with SET ROLE. Need to write PG codec.

                  Or use a whitelist-map approach
                */
                String username = ESAPI.encoder().encodeForSQL(MY_CODEC, authentication.getName());

                Statement statement = pooledConnection.getConnection().createStatement();
                statement.execute("set role \"" + username + "\"");
                statement.close();
            } catch(SQLException exp){
                throw new RuntimeException(exp);
            }
        }
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if("close".equals(method.getName())){
            Statement statement = ((Connection)proxy).createStatement();
            statement.execute("reset role");
            statement.close();
        }

        return super.invoke(proxy, method, args);
    }
}

1
我发现这个答案真正有用的是“ GRANT neil TO webgui;”。意味着webgui成为neil的“成员” ...并且能够执行类似“ ALTER DEFAULT PRIVILEGES”的操作,而我以前是无法做到的。
文斯山

14

1
我试过两个命令都无济于事,如果连接的用户不是超级用户,则会出现权限被拒绝的错误。我已经用其他信息更新了此问题
克里斯·高

2
我相信您的用户必须是您已经要设置的ROLES的成员,并且在其用户上具有NOINHERITS属性,这样它们才不会成为默认设置。然后,您应该升级并降级。但是他们必须已经是ROLE的成员。
rfusca 2010年

1

如果有人仍然需要它(像我一样)。

指定的role_name必须是当前会话用户所属的角色。 https://www.postgresql.org/docs/10/sql-set-role.html

我们需要使当前会话用户成为该角色的成员:

create role myrole;
set role myrole;
grant myrole to myuser;
set role myrole;

产生:

Role ROLE created.


Error starting at line : 4 in command -
set role myrole
Error report -
ERROR: permission denied to set role "myrole"

Grant succeeded.


Role SET succeeded.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.